【发布时间】:2015-06-15 06:51:49
【问题描述】:
我正在尝试在 oracle 中使用 select for update 来防止发生插入。例如,假设在一个会话中(自动提交关闭,隔离级别 = 可序列化)地址表不包含任何行,而我在 SESSION1 中这样做:
SESSION1: select * from Address where addressID = 1 for update
现在在 SESSION2:
SESSION2:insert into Address (addressID, street, city,zip) values (1, 'main','ny','12345'); commit;
我还以为被屏蔽了。但是,我发现插入发生了。我能够做到。然后再次进入 SESSION1。
SESSION1: insert into Address (addressID, street, city,zip) values (1, 'main','ny','12345')
即使在提交之前,这也会产生完整性约束错误。 (不像我预期的那样可序列化的异常)。
为什么会这样?我正在使用 oracle 12c。有几个意想不到的结果。首先,为什么在提交之前我会在 Session1 中收到约束错误? Oracle 不应该看到来自其他会话的插入。其次,Session1中的插入不应该因为“for update”选择而被阻止吗?最后,有没有办法阻止特定键的插入?
【问题讨论】:
-
如果您的
SELECT FOR UPDATE没有锁定行,它不会对包括会话1 在内的任何会话产生任何影响。您要解决的业务问题是什么?您的插入不会使用序列来生成AddressID,从而消除两个会话尝试插入相同AddressID值的可能性吗?为什么要在会话 1 中“保留”一个键值?我想您可以插入一个大部分为空的行,然后再填写数据。但这可能会对空间利用产生一些不幸的影响。 -
请附上会话 1 的 ORA 错误
-
@BarakKedem SQL 错误:ORA-00001:违反了唯一约束 (TEST.SYS_C0010129) 00001。00000 -“违反了唯一约束 (%s.%s)” *原因:尝试了 UPDATE 或 INSERT 语句插入重复键。对于在 DBMS MAC 模式下配置的 Trusted Oracle,如果在不同级别存在重复条目,您可能会看到此消息。 *操作:要么删除唯一限制,要么不插入密钥。
-
@JustinCave 我不一定在这里使用序列。这是我实现 upsert 的方式。之前已经解决过,但我试图按照这里的描述解决它。我的问题是为什么这不起作用。例如,该方法适用于 Mysql 和 Oracle。同样奇怪的是,当事务甚至不应该看到来自会话 2 的插入时(至少在提交之前)会生成重复键异常
-
用 MERGE 语句实现不满意。