在一个表上同时更新和删除

时间:2017-04-03 18:46:10

标签: java oracle hibernate

使用Java,Hibernate和Oracle数据库。 我有两个并发的过程:

  1. Process1从table1中删除一些实体。 (multiple:从table1中删除,其中id = ...)由本机hibernate查询完成。
  2. Process2更新table1中的SAME /其他实体。 (multiple:update table1 set name = ... where id = ...)由jpa repository delete方法完成。
  3. 目前有时候例外

      

    抛出CannotAcquireLockException,
         (SQL错误:60,SQLState:61000 ..
         ORA-00060:等待资源时检测到死锁)

    所以,问题是:发生了什么以及如何避免异常?任何解决方法?

    重要提示:如果发生冲突,我会满意如果删除成功并且更新不会做任何事情。

2 个答案:

答案 0 :(得分:2)

会话A等待B,B等待A - 这就是死锁基本上是什么。 没有什么可以等待的,Oracle杀死了其中任何一个会话。

选项1

创建信号量以有效地序列化并发进程。

create table my_semaphore(dummy char(1));

第1节:

LOCK TABLE my_semaphore in exclusive mode;
UPDATE <your update here>;
COMMIT;

第二节:

LOCK TABLE my_semaphore in exclusive mode;
DELETE <your delete here>;
COMMIT;

选项2 尝试以相同的顺序处理具有两个语句的行,例如rowid或其他。

因此,如果A被B锁定的行卡在后面,那么会话B永远不会返回到A所持有的行。这更加棘手且资源兼容。

答案 1 :(得分:0)

  

“锁定表看起来并不吸引人 - 这就是让severaal进程使用数据库的重点”

显然我们想要启用并发进程。诀窍是设计可以同时运行而不会相互干扰的进程。您的架构未能解决这一问题。进程B不应该更新进程A正在删除的记录。

这是整个网络范式的一个不幸的副作用,它是无国籍的,并且支持乐观的锁定策略。在最后可能的时刻获得锁定“扩展”,但会产生死锁的风险。

另一种选择是悲观的锁定策略,其中会话锁定它想要的行。在Oracle中,我们可以使用SELECT .. FOR UPDATE执行此操作。这会锁定行的子集(由WHERE子句定义的集合),而不是整个表。 Find out more

因此,它不会阻碍对不同数据子集进行操作的并发进程,但会阻止第二个会话获取已经处理的记录。这仍然会导致第二个会话出现异常,但至少会在会话完成任何工作之前发生,并提供重新评估任务的信息(嗯,我们是否要删除这些记录,如果它们正在更新?)

Hibernate支持SELECT FOR UPDATE语法。 This StackOverflow thread discusses it.