在Oracle数据库中持久处理并发请求?

我有这个场景,在航空公司网站上(使用Java)两个独立的客户同时发送两个请求预订同一航空公司的同一个座位
从纽约到芝加哥。 我正在使用oracle数据库并且已提交隔离级别。 我的问题是oracle数据库是否提供了处理这种并发场景的任何解决方案? 我所知道的是,当第一个事务DML语句被触发时,它将在受影响的行上获得锁定,并在事务完成时释放,即在发出回滚或commit时发布。但是一旦提交完成,第二个请求将在第一个完成后立即继续并将覆盖第一个。 所以它没有帮助?

在Java中是的我可以处理将我的db类作为单例并在正在执行更新的方法上使用synchronized关键字。 但是想要知道我们在数据库级别本身是否存在这种问题?可序隔离级别可以帮助。 但不确定?

为了处理网站中的并发性,通常的做法是在每条记录上都有一个允许您检查它的列,因为它已经得到了更新。 上次更新日期或顺序版本号(由触发器自动递增)。

通常,您将读取数据(加上并发列)

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; 

如果允许,它只会过度写入。 你可以尝试类似的东西

 UPDATE seatTable SET seatTaken = true WHERE .. find the seat, flight etc.. AND seatTaken = false 

这将返回第一次更新的1行,之后更新0行。

如您所述,transanction设置将帮助您实现一个操作。 强制执行此类限制的最佳方法是确保关系模型在第一个操作成功后不会接受第二个操作。

比如更新….座位=“被拍摄”,而不是必须对行进行更新,创建一个具有约束的保留表(客户,航class,座位)(列:座位=唯一)(查找ora docs to学习表创建的语法。 这样,您的预订流程就会成为预订表中的插入内容,您可以依赖RDBMS来强制执行关系约束,以保持业务模型的有效性。

例如,让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的唯一方法是首先删除之前的预订,这可能是您的业务流程想要实现的。

除了通过精心制作WHERE子句在单个UPDATE执行所有操作,您可以执行以下操作:

交易1:

  • SELECT ... FOR UPDATE在事务持续时间内专门锁定行。
  • 检查行的返回状态是否为“已预订”,如果是,则退出(或重试另一行)。
  • UPDATE行并将其“状态”设置为“已预订” – 保证在此期间没有其他人更新它。
  • 承诺。 这将删除独占锁。

交易2:

  • SELECT ... FOR UPDATE 阻塞,直到事务1完成,然后排他地锁定行。
  • 行的返回状态为“已预订”(因为事务1以这种方式标记),因此退出(或可能重试另一行)。