我在oracle 11g中有这个表。
TABLE: ORDER_LOCK
Name Null Type
---------------------- -------- ----------
ORDER_ID NOT NULL NUMBER(10) [PRIMARY KEY]
ORDER_REF_ID NUMBER(10) [UNIQUE KEY]
ORDER_MSG_SENT NUMBER(1)
merge into ORDER_LOCK al
using ( select ? ORDER_REF_ID, ? ORDER_MSG_SENT from dual ) t
on (al.ORDER_REF_ID = t.ORDER_REF_ID)
when not matched then
insert (ORDER_ID, ORDER_REF_ID, ORDER_MSG_SENT)
values (ORDER_LOCK_SEQ.nextval, t.ORDER_REF_ID, t.ORDER_MSG_SENT)
我在我的应用程序(Java)中使用上面的Merge。合并调用发生在多个线程中。代码一直工作正常但昨天我们在唯一键'ORDER_REF_ID'上遇到了约束违规(ORA-00001)。
Merge语句有问题吗?或者,当上述Merge语句可能导致约束违规时,是否存在任何特定情况?
由于
普什卡
答案 0 :(得分:0)
如果您有两个尝试插入相同ORDER_REF_ID的会话(在您的情况下是Java线程),则会发生这种情况。请考虑以下情形:
1)会话1执行此MERGE语句(不提交):
merge into ORDER_LOCK al
using ( select 1 ORDER_REF_ID, sysdate ORDER_MSG_SENT from dual ) t
on (al.ORDER_REF_ID = t.ORDER_REF_ID)
when not matched then
insert (ORDER_ID, ORDER_REF_ID, ORDER_MSG_SENT)
values (ORDER_LOCK_SEQ.nextval, t.ORDER_REF_ID, t.ORDER_MSG_SENT);
2)会话2启动相同的MERGE语句:
merge into ORDER_LOCK al
using ( select 1 ORDER_REF_ID, sysdate ORDER_MSG_SENT from dual ) t
on (al.ORDER_REF_ID = t.ORDER_REF_ID)
when not matched then
insert (ORDER_ID, ORDER_REF_ID, ORDER_MSG_SENT)
values (ORDER_LOCK_SEQ.nextval, t.ORDER_REF_ID, t.ORDER_MSG_SENT);
(这将尝试插入行,因为会话2没有“看到”会话1中未提交的更改。会话2将阻止,因为它正在等待会话1持有的锁定):
3)第1节提交
=>会话2现在尝试执行插入,这将引发ORA-00001:UNIQUE CONSTRAINT VIOLATION,因为ORDER_REF_ID 1已经存在
<强>更新强>
要解决这个问题,我建议您修改应用程序并在Java线程和ORDER_REF_ID之间引入某种关联 - 每个ORDER_REF_ID应该“属于”一个线程,并且该线程应该专门为其插入/更新数据ORDER_REF_ID。