Procedure中關鍵code如下:
---------------------------------------
lock table tb_book_ticket in share mode;
...
insert into tb_book_ticket (id, scheduled_flight, ticket_no, book_time) values (ID.nextval, v_scheduled_flight, v_ticket_no, SYSDATE); -- mark1
... -- mark2
select count(*) into v_book_count from tb_book_ticket where scheduled_flight = v_scheduled_flight; -- mark3
if v_book_count <= v_book_max_count then
v_result := 'book successfully';
commit;
else
v_result := 'book unsuccessfully';
rollback;
end if;
return v_result;
-------------------------------------------------------------
以上有2個地方需注意:
1) 采用 lock table table_name in share mode 方式而非 lock table table_name in exclusive mode 提高並發性處理, 盡量減少不必要執行等待.
2) 按常規思路, 可能會將 mark1 與 mark3 順序交換, 但此舉不行
-------------------------------------------------------------
select count(*) into v_book_count from tb_book_ticket where scheduled_flight = v_scheduled_flight; -- mark3
... -- mark2
if v_book_count < v_book_max_count then
insert into tb_book_ticket (id, scheduled_flight, ticket_no, book_time) values (ID.nextval, v_scheduled_flight, v_ticket_no, SYSDATE); -- mark1
-- mark4
commit;
end if;
-------------------------------------------------------------
試想若 userA 執行到 mark4, 而同時 userB 執行到 mark3, 就可能會出現由於 userA 尚未commit 而導致 userB 訂到機票但實際沒有座位的情況。
若確希望使用常規邏輯來實現, 需要用到 Oracle 的表的讀鎖功能 (精細訪問策略), 而此非本文范圍, 且其對於SYS用戶無效。