【问题标题】:How to lock oracle table on WHERE condition?如何在 WHERE 条件下锁定 oracle 表?
【发布时间】:2015-06-24 17:05:34
【问题描述】:

我的ORACLE 数据库中有一个表INFO_TABLE 有3 个字段(id, param1, param2)

我使用这个表的方式如下

`1) SELECT ID FROM INFO_TABLE WHERE param1 = ? param2 = ?` <br>
2) IF ROW EXISTS, THEN I USE IT <br>
3) if row does not exist i execute this query : 
INSERT INTO INFO VALUES (INFO_SEQ.NEXTVAL, 'val1', 'val2' and return the generated id for this row

问题是,当我在并发模式下执行此操作时,有机会将 ('val1', 'val2') 的重复值对插入到表中。

有什么办法可以将表锁定在WHERE 谓词上以避免这种情况?

我不想为此操作锁定整个表,并且我不能使用唯一约束。
我需要SELECT FOR UPDATE 之类的东西(这个不起作用,因为还没有要锁定的行)查询

【问题讨论】:

  • 为什么val1val2 对没有唯一索引?
  • 如果您告诉我们为什么无法使用唯一约束,则可能有解决方法。例如,如果您需要保持某些历史值不唯一,但希望对所有未来值应用唯一性,则可以通过将索引创建为novalidate 来实现。类似的例子见我的回答here

标签: sql oracle


【解决方案1】:

您在 ('val1', 'val2') 上添加一个唯一约束,这将防止输入重复项。否则会引发 ORA-0001 错误。

如果你不能这样做,那么你就没有办法防止重复输入。

【讨论】:

  • 不幸的是,正如我之前所说,这不是我的选择。我将不得不在 JDBC 代码中捕获这个异常,并将一些业务逻辑放入非常不可取的 catch 块中
  • 那么你没有可靠的方法来解决这个问题,因为不同的会话永远无法看到或推断其他会话未提交的事务,除了通过约束机制。数据库“允许”约束以查看未提交的事务。使用触发器也不会为您解决这个问题,因为它们在会话的事务中执行,因此它们也无法推断出其他未提交事务的任何内容。
  • 另外,MERGE 语句不能保证是原子的——它们也可能导致重复。
  • 看起来捕获异常是唯一的方法......感谢您的回答
【解决方案2】:

我完全同意另一个答案,即在面对并发插入时,您将需要一个独特的约束来确保数据完整性。

但是,如果您不想在 Java 代码中处理异常,您可以将插入逻辑封装在 PL/SQL 过程中,并让它处理异常。

假设您已经正确定义了对 param1param2 的唯一约束,那么您可以使用如下所示的过程:

create or replace procedure get_info_table_id_for(param1Value in varchar2, param2Value in varchar2, IdValue out number)
as
begin
  begin
    select Id into IdValue
    from info_table
    where param1 = param1Value
    and param2 = param2Value;
  exception
    when no_data_found then
      IdValue := null;
  end;

  if IdValue is null then
    IdValue := info_seq.nextval;

    begin
      insert into info_table (Id, param1, param2) values (IdValue, param1Value, param2Value);
    exception
      when dup_val_on_index then -- concurrent insert, reselect the row.
        select Id into IdValue
        from info_table
        where param1 = param1Value
        and param2 = param2Value;
    end;
  end if;
end get_info_table_id_for;
/

唯一约束违反异常在when dup_val_on_index then块中处理。

【讨论】:

  • 我想我会尝试插入并捕获任何异常。代码更少,效率更高。
猜你喜欢
  • 1970-01-01
  • 2019-12-09
  • 2015-05-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多