使用Java,Hibernate和Oracle数据库。 我有两个并发的过程:
目前有时候例外
抛出CannotAcquireLockException,
(SQL错误:60,SQLState:61000 ..
ORA-00060:等待资源时检测到死锁)
所以,问题是:发生了什么以及如何避免异常?任何解决方法?
重要提示:如果发生冲突,我会满意如果删除成功并且更新不会做任何事情。
答案 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.