-1

这是使用 libpq.so 的伪代码;但它并不像我想的那样。

transaction begin

re1 = [select ics_time from table1 where c1=c11, c2=c22, c3=c33, c4=c44 for update];

if(re1 satisfies the condition)
{
   re2 = [select id where c1=c11, c2=c22, c3=c33, c4=c44 for update];
   delete from table1 where id = re2;
   delete from table2 where id = re2;
   delete from table3 where id = re3;
   insert a new record into table1,table2,table3 with the c1,c2,c3,c4 as primary keys;
]
commit or rollback

注意c1,c2,c3,c4在数据库中都设置为主键,所以数据库中只有一行有这些键。

让我感到困惑的是:

  1. 有两个“选择更新”将锁定同一行。在这段代码中,第二条 SQL 语句是否等待被第一条语句阻塞的排他锁?但是,实际情况是它并没有发生。
  2. 发生了一些出乎我意料的事情。在日志中,我看到大量重复插入错误。在我看来,“选择更新”用唯一的键锁定行,两个过程连续进行。插入操作在删除之后进行。这些重复插入是如何发生的?“select for update”不是为该行添加了一个排他锁,这会阻止所有其他想要锁定同一行的进程吗?
4

1 回答 1

4

关于您的第一点:语句不持有锁,周围事务持有锁。您的伪代码似乎对一个事务使用一个连接,而该事务又使用多个语句。所以第二个SELECT FOR UPDATE不会被第一个阻止。阅读有关锁定的文档

[...]当行被更新或删除时,会自动获取特定行的排他行级锁。锁一直保持到事务提交或回滚,就像表级锁一样。行级锁不影响数据查询;他们只阻止同一行的作者。

否则,如果交易可以如此轻易地阻止自己,那将是非常有趣的。

关于你的第二点:我无法回答这个问题,因为a)你的伪代码是针对这个问题的伪代码,b)我不明白你所说的“进程”和确切的用例是什么意思。

于 2013-03-31T07:14:28.980 回答