我有这种情况,在航空公司网站上(使用Java)两个独立的客户同时发送两个请求预订同一航空公司的同一个座位
从纽约到芝加哥。我正在使用oracle数据库并且读取了隔离级别。我的问题是oracle数据库提供的
处理这种并发场景的任何解决方案?我所知道的是当第一个事务DML语句被触发时它会锁定受影响的
当事务完成时,即在发出回滚或提交时将释放行。但是一旦提交完成,第二个请求将立即继续
第一个完成并将覆盖第一个。所以它没有帮助?
在Java中是的我可以处理将我的db类作为单例并在正在执行更新的方法上使用synchronized关键字。 但想知道是否存在 无论如何我们可以在数据库级别本身出现这种问题吗?可序隔离级别可以帮助。但不确定?
答案 0 :(得分:5)
只有你允许它才会过度写。你可以试试像
这样的东西UPDATE seatTable
SET seatTaken = true
WHERE .. find the seat, flight etc.. AND seatTaken = false
这将返回第一次更新的1行,之后更新0行。
答案 1 :(得分:2)
正如您所提到的,transanction设置将帮助您实现一个操作。强制执行此类限制的最佳方法是确保关系模型在第一个操作成功后不会接受第二个操作。
而不是必须对某行进行更新,比如说更新......座位=“拍摄”,创建一个有约束的保留表(客户,航班,座位)(列:座位=唯一)(查找ora docs学习表创建的语法)。这样,您的预订流程就会成为预订表中的插入内容,您可以依赖RDBMS来强制执行关系约束,以保持业务模型的有效性。
e.g。设t1为较早的操作时间,您将拥有:
t1=> insert into reservations(customer1,flight-x,seat-y) // succeeds. Customer 1 reserved the seat-y
t2=> insert into reservations(customer2,flight-x,seat-y) // fails with RDBMS unique constrain violated.
再次保留seat-y
的唯一方法是首先删除之前的预订,这可能是您的业务流程想要实现的目标。
答案 2 :(得分:1)
要在网站中处理并发,通常的做法是在每条记录上都有一个允许您检查它的列,因为您已经获得它。上次更新日期或顺序版本号(由触发器自动递增)。
通常,您将读取数据(加上并发列)
SELECT seat,etc,version_no
FROM t1
WHERE column = a_value
然后,当用户最终开始预订座位时,除非有更新,否则更新将会有效。
(每次更新后版本号或更新日期都会更改)
BEGIN
UPDATE t1
SET seatTaken = true
WHERE seatid = .....
AND version_no = p_version
RETURNING version_no INTO p_version;
EXCEPTION WHEN NOT_FOUND THEN
--Generate a custom exception
--concurrency viloation the record has been updated already
END;
自动更新版本号的触发器看起来有点像这样
CREATE OR REPLACE TRIGGER t1_version
AFTER INSERT OR UPDATE ON t1
FOR EACH ROW
BEGIN
IF :new.version_no IS NULL THEN
:new.version_no := 0;
ELSE
:new.version_no := :old.version_no + 1;
END IF;
END;
答案 3 :(得分:1)
除了通过精心制作UPDATE
子句在单个WHERE
中执行所有操作外,您还可以执行以下操作:
交易1:
SELECT ... FOR UPDATE
在事务持续期间独占锁定行。UPDATE
行并将其“状态”设置为“已预订” - 保证在此期间没有其他人更新它。交易2:
SELECT ... FOR UPDATE
阻止,直到事务1完成,然后专门锁定该行。