小编典典

数据库是否总是在查询或更新后锁定不存在的行?

sql

鉴于:

customer[id BIGINT AUTO_INCREMENT PRIMARY KEY, email VARCHAR(30), count INT]

我想自动执行以下操作:更新客户(如果已经存在);否则,插入一个新客户。

从理论上讲,这听起来似乎非常适合SQL-
MERGE,
但是我正在使用的数据库不支持将AUTO_INCREMENT列与MERGE配合使用。

似乎表明,如果对不存在的行执行查询或更新语句,数据库将锁定索引,从而防止并发插入。

SQL标准可以保证这种行为吗?是否有任何数据库无法以这种方式运行?

更新 :对不起,我应该早先提到:解决方案必须使用READ_COMMITTED事务隔离, 除非
这是不可能的,在这种情况下,我将接受使用SERIALIZABLE。


阅读 173

收藏
2021-05-05

共1个答案

小编典典

回答我自己的问题,因为围绕该主题似乎有很多困惑。看起来:

-- BAD! DO NOT DO THIS! --
insert customer (email, count) 
select 'foo@example.com', 0
where not exists (
      select 1 from customer
      where email = 'foo@example.com'
)

对竞争条件开放。从我所能收集的资料来看,这个问题的唯一可移植的解决方案是:

  1. 选择一个要合并的键。这可以是主键,也可以是另一个唯一键,但是 必须 具有唯一约束。
  2. 尝试insert新的一行。您必须捕获如果该行已存在将发生的错误。
  3. 困难的部分结束了。在这一点上,可以确保该行存在,并且由于对它持有写锁定(由于insert上一步中的),因此可以保护您免受竞争条件的影响。
  4. 继续,update如果需要或使用select它的主键。
2021-05-05