【问题标题】:Concurrent Insert and Update postgres并发插入和更新 postgres
【发布时间】:2016-04-20 15:06:32
【问题描述】:

当您在多线程环境中收到同一字段的并发插入和更新时,有没有办法解决问题。

例子

线程 1

BEGIN 
insert into users (name,age) values('spiderman',27)
COMMIT

线程 2

BEGIN
 update into users set age = 26 where name='spiderman';
COMMIT

大多数时候 update(transaction) 不知道插入的发生,因此它会抛出错误。

我在这里看到的是竞争条件的经典示例,避免竞争条件的一种方法是使用有效锁。

如何在数据库中尚不存在的记录上应用锁(记录)。

在上面的插入语句示例中,更新知道该记录还没有在数据库中。

【问题讨论】:

标签: multithreading postgresql concurrency


【解决方案1】:

基于锁的解决方案会非常困难,而且可能不值得这么麻烦。您必须找到一种方法来创建一组包含所有可能的“名称”字段的数据,然后围绕该数据创建一个咨询锁定系统。它也可能容易出错。

但是,如果问题确实是确保 UPDATEINSERT 之后才能运行,则有更简单的解决方案。

具体来说,想到的是这样的:

BEGIN;
  SELECT count(*) FROM users WHERE name = 'spiderman';
  -- on the application side, check to see what the result is
  -- if it's 0, ROLLBACK
  -- if it's >0:
  UPDATE users SET age = 26 WHERE name = 'spiderman';
COMMIT;

如果您最终回滚,您可以稍后再回来重试,无论这意味着简单的操作,例如 sleep 10 秒后重试,还是更复杂的操作,例如将工作项放回队列并继续用不同的作品。

如果您担心SELECTUPDATE 之间发生更新,您可以SELECT FOR UPDATE,这将锁定选定的行直到您的事务完成。

【讨论】:

  • 我们通常不会遇到这种情况,因此引入睡眠会影响几乎所有插入。我不能在更新时选择,因为这里发生的并发操作是插入和更新。选择不是查询计划的一部分。
  • 我能想到的一种方法是将事务隔离级别设置为 diry uncommitted 您对此有何看法?
  • 您使用的是什么版本的 postgresql?如果是 9.5,那么现在有一个“upsert”功能,它可以与 SETNX 类似地工作。语法是这样的:INSERT INTO users (name, age) VALUES ('spiderman', 26) ON CONFLICT (name) DO UPDATE SET age = 26; 这能满足你的需要吗?
  • 我不确定我是否理解您最近的评论。 SETNX 是令人困惑的事情,我认为——这将设置一个值仅当该键不存在时。如果它确实存在,那么它将什么都不做。如果你SETNX foo 27,然后SETNX foo 26,“foo”的值将是 27,因为它存在。这是你想要的行为吗?因为这似乎与您在原始帖子中描述的不同。我最初认为您想要的是让两个线程都成功地对数据库进行更改。我提供了几种方法来做到这一点。这是你需要的吗?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2017-08-23
  • 1970-01-01
  • 1970-01-01
  • 2010-10-03
  • 2016-03-13
  • 2019-08-07
  • 1970-01-01
相关资源
最近更新 更多