在MySQL中递增一个字段是原子的吗?

New*_*ewb 33 mysql atomic increment thread-safety

我正在建立一个网站,我想在标准的MyISAM表中增加一个计数器.

简化示例:

UPDATE votes SET num = num + 1;
Run Code Online (Sandbox Code Playgroud)

如果多个连接正在执行相同的查询,这会导致问题,还是MySQL会处理它并锁定表或某些东西以确保没有冲突?

Tra*_*ago 23

写入是原子的,但增量也需要读取.所以问题是:你确定读取是安全的吗?换句话说,你确定另一个做增量的线程最终不会以相同的值递增吗?我有疑问.这样做的100%正确方法是.

-- begin transaction here

select counter from myCounters where counter_id = 1 FOR UPDATE;

-- now the row is locked and nobody can read or modify its values

update myCounters set counter = ? where id = 1;

-- set ? to counter + 1 programmatically

commit; -- and unlock...
Run Code Online (Sandbox Code Playgroud)

  • @Nicholi 不,你错了。在[MySQL手册](https://dev.mysql.com/doc/refman/5.5/en/innodb-locking-reads.html)中提到了`UPDATE SET field = field + 1`的这个例子,手册说: **“不要使用一致读取或共享模式读取来读取计数器的当前值,因为数据库的两个用户可能会看到计数器的相同值”** .您必须在更新之前锁定该行,就像这个答案一样,如果您不希望在重负载下出现非常讨厌的错误。 (6认同)
  • 我相当确定 UPDATE SET field = field + 1 的 OP 示例不会导致任何并发问题,但这是确保您在修改字段时锁定行/表的最佳方法。但是,当您进行更复杂的操作时,通常更有意义。 (2认同)

Lac*_*lev 15

MyISAM表使用表级锁定.这意味着在执行更新查询期间将锁定整个表.因此,简化用例的答案是:是的,这是线程安全的.但是,如果您使用其他存储引擎或者您的更新包含多个表,则可能不是这种情况.

以下是MySQL手册中的引用,以便更清晰:

表锁定允许多个会话同时从表中读取,但如果会话想要写入表,则必须首先获得独占访问权.在更新期间,要访问此特定表的所有其他会话必须等到更新完成.

如果适合您的设计,您还可以考虑使用自动增量列,事务或外部同步.

干杯!


gra*_*rks 6

是的,执行更新查询时,表(或InnoDB格式数据库中的行)会自动锁定.


Ign*_*ams 5

这种形式UPDATE是原子的。其他形式的UPDATE可以通过使用事务与 SELECT ... FOR UPDATE.