【问题标题】:READ COMMITTED database isolation level in oracleoracle中的READ COMMITTED数据库隔离级别
【发布时间】:2010-11-30 13:49:23
【问题描述】:

我正在开发一个连接到 oracle 的网络应用程序。我们在 oracle 中有一个表,其中有一列“已激活”。任何时候只有一行可以将此列设置为 1。为了强制执行这一点,我们一直在 Java 中使用 SERIALIZED 隔离级别,但是我们遇到了“无法序列化事务”错误,并且无法找出原因。

我们想知道 READ COMMITTED 的隔离级别是否可以完成这项工作。所以我的问题是:

如果我们有一个涉及以下 SQL 的事务:

SELECT *
FROM MODEL;

UPDATE MODEL
SET ACTIVATED = 0;

UPDATE MODEL
SET ACTIVATED = 1
WHERE RISK_MODEL_ID = ?;

COMMIT;

鉴于可能同时执行多个这些事务,是否有可能将多个 MODEL 行的激活标志设置为 1?

任何帮助将不胜感激。

【问题讨论】:

    标签: sql oracle transactions isolation-level read-committed


    【解决方案1】:

    您的解决方案应该有效:您的第一次更新将锁定整个表。如果另一个事务没有完成,更新将等待。您的第二次更新将保证只有一行的值为 1,因为您正在锁定表(但它不会阻止 INSERT 语句)。

    您还应确保存在带有RISK_MODEL_ID 的行(否则在事务结束时您将有零行且值为“1”)。

    为防止并发 INSERT 语句,您将 LOCK 表(在独占模式下)。

    【讨论】:

    • 类似,但我会在独占模式下锁定模型并执行 UPDATE MODEL SET ACTIVATED = 0 WHERE ACTIVATED = 1 更新的行数较少,因此性能略高,并且 LOCK TABLE 会阻止桌子上的并发活动。
    【解决方案2】:

    您可以考虑使用唯一的、基于函数的索引来让 Oracle 处理只有一行且激活标志设置为 1 的约束。

    CREATE UNIQUE INDEX MODEL_IX ON MODEL ( DECODE(ACTIVATED, 1, 1, NULL));
    

    这将停止将标志设置为 1 的不止一行,但并不意味着始终有一行将标志设置为 1。

    【讨论】:

      【解决方案3】:

      如果您想要确保一次只能运行一个事务,那么您可以使用FOR UPDATE 语法。由于您有单行需要锁定,因此这是一种非常有效的方法。

      declare
          cursor c is 
              select activated
              from model
              where activated = 1
              for update of activated;
          r c%rowtype;
      begin
          open c;
          --  this statement will fail if another transaction is running
          fetch c in r;
          ....
          update model
          set activated = 0
          where current of c;
      
          update model
          set activated = 1
          where risk_model_id = ?;
      
          close c;
      
          commit;
      end;
      /
      

      commit 释放锁。

      默认行为是等到该行被释放。否则我们可以指定NOWAIT,在这种情况下,任何其他尝试更新当前活动行的会话都将立即失败,或者我们可以添加带有轮询时间的WAIT 选项。 NOWAIT 是选择绝对避免挂起风险的选项,它也让我们有机会通知用户其他人正在更新表格,他们可能想知道。

      这种方法比更新表中的所有行更具可扩展性。使用 WW 显示的基于函数的索引来强制执行只有一行可以具有 ACTIVATED=1 的规则。

      【讨论】:

        猜你喜欢
        • 2019-06-18
        • 1970-01-01
        • 2014-09-18
        • 1970-01-01
        • 2012-07-04
        • 2015-08-02
        • 1970-01-01
        • 2020-02-13
        • 2011-04-22
        相关资源
        最近更新 更多