【问题标题】:DB : perform an update query after a fetch one inside a transactionDB:在事务中获取一个后执行更新查询
【发布时间】:2015-06-18 13:58:24
【问题描述】:

我正在开发一个 IBM DB,但我认为这些概念几乎相同。

我想获取一行,返回这些数据(或者将它们保存到变量中)并更新该特定行的一些字段。可能有许多实例尝试同时执行该查询,因此我们需要将提取操作设为原子操作。

每一行都有一个名为pending的字段,初始化为FALSE。当一个实例获取这一行时,它被设置为 TRUE(这就是我想要做的更新)。我需要它也是原子的原因是我的查询获取表的第一行,其中未决是 FALSE。

在伪代码中我有这样的东西:

OPEN_DB(myDb, "DBNAME");  // opening the DB
BEGIN_TRANSACTION(myDb);  // beginning transaction on my db
EXECUTE_QUERY(myDb,"SELECT * FROM tbname WHERE pending == 0 ORDER BY colid LIMIT 1");
... assign a cursor to my results
while (valid_data) {
    // assign column fields to variable

    // and here i want to do the update for this column
    // I guess the problem is here
     EXECUTE_QUERY(myDb,"UPDATE tbname SET pending = 1 WHERE colid=@colid")

}
COMMIT();

不用担心语法,它们是宏,一旦单独执行,它们就可以工作。我猜问题出在第二个查询上,但为什么?

  • 我应该先提交然后执行第二个查询吗?
  • 如果是,那么如何确保在更新之前不会有其他实例读取同一行?

我想这与我使用的数据库无关。

如果我评论第二个,代码就可以工作。如果我单独执行第二个,它也可以工作。

【问题讨论】:

    标签: sql database transactions ibm-db2


    【解决方案1】:

    选项 1 - 为光标执行 select for update,这将是悲观锁定

    选项 2 - 做一个乐观锁并处理异常。锁需要一个类似于上次更新时间或版本的列,如下所示:

    OPEN CURSOR
    
    UPDATE table set col = :new_value
    WHERE id = :id_from_cursor
    last_updated = :last_updated_from_cursor;
    
    CHECK if update row count == 1 COMMIT
    IF not throw exception
    

    虽然我认为选项 1 应该可以很好地工作,除非您在选择和更新之间有很大的时间间隔

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2015-01-10
      • 2016-02-29
      • 2011-06-19
      • 2013-03-23
      • 2015-12-01
      • 1970-01-01
      • 2012-07-15
      • 1970-01-01
      相关资源
      最近更新 更多