数据库:在事务中获取一个后执行更新查询
DB : perform an update query after a fetch one inside a transaction
我在 IBM 数据库上工作,但我认为概念几乎相同。
我想获取单行,return 这些数据(或者说将它们保存到变量中)并更新该特定行的某些字段。可能有多个实例同时尝试执行该查询,因此我们需要获取操作是原子的。
每一行都有一个字段叫pending,初始化为FALSE。当一个实例获取这一行时,它被设置为 TRUE(这是我想要做的更新)。我需要它也是原子的原因是我的查询获取 table 的第一行,其中 pending 为 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();
不用担心语法,它们是宏,一旦单独执行它们就可以工作。我猜问题出在第二个查询上,但为什么呢?
- 我应该先提交然后执行第二个查询吗?
- 如果是,那么我如何确保在更新之前没有其他实例读取同一行?
我想这与我使用的数据库无关。
如果我评论第二个,代码就可以工作。如果我单独执行第二个,它也能正常工作。
选项 1 - 为 curor 做一个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 应该很好用,除非你在 select 和更新
之间有很大的时间间隔
我在 IBM 数据库上工作,但我认为概念几乎相同。
我想获取单行,return 这些数据(或者说将它们保存到变量中)并更新该特定行的某些字段。可能有多个实例同时尝试执行该查询,因此我们需要获取操作是原子的。
每一行都有一个字段叫pending,初始化为FALSE。当一个实例获取这一行时,它被设置为 TRUE(这是我想要做的更新)。我需要它也是原子的原因是我的查询获取 table 的第一行,其中 pending 为 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();
不用担心语法,它们是宏,一旦单独执行它们就可以工作。我猜问题出在第二个查询上,但为什么呢?
- 我应该先提交然后执行第二个查询吗?
- 如果是,那么我如何确保在更新之前没有其他实例读取同一行?
我想这与我使用的数据库无关。
如果我评论第二个,代码就可以工作。如果我单独执行第二个,它也能正常工作。
选项 1 - 为 curor 做一个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 应该很好用,除非你在 select 和更新
之间有很大的时间间隔