Multithreading 并发插入和更新postgres
当您在多线程环境中收到同一字段的并发插入和更新时,有没有解决问题的方法 范例 线程1Multithreading 并发插入和更新postgres,multithreading,postgresql,concurrency,Multithreading,Postgresql,Concurrency,当您在多线程环境中收到同一字段的并发插入和更新时,有没有解决问题的方法 范例 线程1 BEGIN insert into users (name,age) values('spiderman',27) COMMIT 线程2 BEGIN update into users set age = 26 where name='spiderman'; COMMIT 大多数情况下,更新(事务)不知道发生了插入,因此会抛出错误 我在这里看到的是竞争条件的经典示例,避免竞争条件的一种方法是使用有效锁
BEGIN
insert into users (name,age) values('spiderman',27)
COMMIT
线程2
BEGIN
update into users set age = 26 where name='spiderman';
COMMIT
大多数情况下,更新(事务)不知道发生了插入,因此会抛出错误
我在这里看到的是竞争条件的经典示例,避免竞争条件的一种方法是使用有效锁
如何对数据库中尚不存在的记录应用锁(记录)
在上面的insert语句示例中,Update知道记录还不在DB中。基于锁的解决方案将非常困难,可能不值得费心。您必须找到一种方法来创建一组包含所有可能的“名称”字段的数据,然后围绕该数据创建一个建议锁定系统。它也可能容易出错 但是,如果问题真的是要确保
更新在插入之后才会运行,那么有更简单的解决方案
具体来说,我想到的是:
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;
如果您最终回滚,您将返回并稍后重试,这可能意味着一些简单的操作,如睡眠10秒并重试,或者更复杂的操作,如将工作项放回队列并继续执行不同的工作
如果您担心在SELECT
和UPDATE
之间发生更新,您可以SELECT FOR UPDATE
,这将锁定所选行,直到事务完成。基于锁定的解决方案将非常困难,可能不值得费事。您必须找到一种方法来创建一组包含所有可能的“名称”字段的数据,然后围绕该数据创建一个建议锁定系统。它也可能容易出错
但是,如果问题真的是要确保更新在插入之后才会运行,那么有更简单的解决方案
具体来说,我想到的是:
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;
如果您最终回滚,您将返回并稍后重试,这可能意味着一些简单的操作,如睡眠10秒并重试,或者更复杂的操作,如将工作项放回队列并继续执行不同的工作
如果您担心在SELECT
和UPDATE
之间发生更新,您可以SELECT FOR UPDATE
,这将锁定所选行,直到事务完成。在web环境中,使用(请参阅JPA中的@Version注释)在web环境中,使用(请参阅JPA中的@Version注释)我们通常没有这种情况,所以引入睡眠会影响几乎所有的人。我不能在更新时选择,因为这里发生的并发操作是插入和更新。Select不是查询计划的一部分。我能想到的一种方法是将事务隔离级别设置为diry uncommitted。对此,您有何看法?您使用的是什么版本的postgresql?如果是9.5,那么现在就有了一个“upsert”功能,它的工作原理与SETNX类似。语法如下:在用户(姓名、年龄)值('spiderman',26)中插入冲突(姓名)DO UPDATE SET age=26
这能满足您的需要吗?我的印象是,upsert
对concurrentinsert
保持正确,至少这是我在提出问题之前阅读它时理解的。我不确定我是否理解您最近的评论SETNX
让人困惑,我认为——只有在键不存在的情况下才会设置值。如果它真的存在,那么它将一事无成。如果SETNX foo 27
,然后SETNX foo 26
,则“foo”的值将为27,因为它存在。这是你想要的行为吗?因为这似乎与你在原始帖子中描述的有所不同。我最初认为您希望两个线程都能成功地对数据库进行更改。我已经提供了几种方法来做到这一点。这就是你所需要的吗?我们通常没有这种情况,所以引入睡眠会影响几乎所有人。我不能在更新时选择,因为这里发生的并发操作是插入和更新。Select不是查询计划的一部分。我能想到的一种方法是将事务隔离级别设置为diry uncommitted。对此,您有何看法?您使用的是什么版本的postgresql?如果是9.5,那么现在就有了一个“upsert”功能,它的工作原理与SETNX类似。语法如下:在用户(姓名、年龄)值('spiderman',26)中插入冲突(姓名)DO UPDATE SET age=26
这能满足您的需要吗?我的印象是,upsert
对concurrentinsert
保持正确,至少这是我在提出问题之前阅读它时理解的。我不确定我是否理解您最近的评论SETNX
让人困惑,我认为——只有在键不存在的情况下才会设置值。如果它真的存在,那么它将一事无成。如果SETNX foo 27
,然后SETNX foo 26
,则“foo”的值将为27,因为它存在。这是你想要的行为吗?因为这似乎与你在原始帖子中描述的有所不同。我最初认为您希望两个线程都能成功地对数据库进行更改。我已经提供了几种方法来做到这一点。这就是你需要的吗?