【问题标题】:some questions about "select for update"?关于“选择更新”的一些问题?
【发布时间】:2013-03-31 15:26:58
【问题描述】:

这是使用 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. 出乎我的意料。在日志中,我看到一个大 重复插入错误的数量。在我看来,“选择 for update " 用唯一的 for 键锁定行,两个过程 依次进行。插入操作在删除之后进行。这些怎么可能 出现重复插入? “选择更新”是否添加了一个 该行的排他锁,它阻塞所有其他进程 想要锁定同一行?

【问题讨论】:

  • 你的伪代码没有意义。您没有过滤 SELECT FOR UPDATE 中的任何行。您说有问题的表上的主键是(c1,c2,c3,c4),但随后被一些新列“id”删除。尝试提供实际显示问题的实际 SQL。
  • id是连接table1、table2和table3的外键,id是从第二个“select for update”中选择的。这有什么意义吗?@RichardHuxton
  • 不,这怎么可能?您没有在第二个“选择更新”中选择“id”,以后也没有插入它。显示一些重现问题的实际 SQL,然后人们就会明白你的意思。
  • 对不起,我在伪代码中犯了一些错误,现在更正了,有意义吗?@RichardHuxton
  • 否 - 仍然存在明显错误。请只发布显示问题的真实 SQL。

标签: postgresql


【解决方案1】:

关于您的第一点:语句不持有锁,周围事务持有锁。您的伪代码似乎对一个事务使用一个连接,而该事务又使用多个语句。所以第二个SELECT FOR UPDATE 不会被第一个阻止。请阅读docs about locking 了解此内容:

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

否则,如果一个交易可以这么容易地阻止自己,那就太可笑了。

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

【讨论】:

  • 我运行了多个进程或线程,其中包含上面的伪代码,所以,多进程可以看作是连接到数据库的多用户。这有什么意义吗? @A.H.
  • 对不起,我在上面的伪代码中出错了,现在已经更正了,你看清楚了吗? @A.H.
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2013-09-10
  • 1970-01-01
  • 1970-01-01
  • 2022-01-19
  • 2011-10-12
  • 1970-01-01
  • 2018-05-24
相关资源
最近更新 更多