【发布时间】:2011-12-06 21:13:12
【问题描述】:
不使用显式事务,是:
update tokens set tokens = tokens + 1
保证在 InnoDB 中是原子的?
【问题讨论】:
标签: mysql thread-safety innodb atomic
不使用显式事务,是:
update tokens set tokens = tokens + 1
保证在 InnoDB 中是原子的?
【问题讨论】:
标签: mysql thread-safety innodb atomic
我的理解是,在自动提交模式下(即“没有显式事务”),单个语句就是单个事务。由于事务按照定义是原子的,因此您的单个语句也是原子的。
但是,在评估约束时,这不是在语句(即事务)级别上进行的,而是在处理语句时逐行进行。
如果您在 tokens 列上有一个唯一约束(索引),那么该更新很可能会因此而失败。对于引用同一个表的外键也是如此。
【讨论】:
child_codes 中有一行),SELECT ... FOR UPDATE(采用排他锁/写锁)是为了序列化相对于其他会话的 SELECT/UPDATE 组合(即:使整个 SELECT/UPDATE 原子和一致)。
我认为不是。没有我的 MySQL 隔离级别/备忘单,但我认为它在每行级别上是原子的(UPDATE 将使用范围锁 IIRC),但不是在每个表级别上。
现在,比 UPDATE 是否是原子的更有趣的问题是,UPDATE 的非原子性何时可观察。答案是READ UNCOMMITTED隔离级别的单个语句可以观察到UPDATE的非原子性,而READ COMMITTED隔离级别的单个事务中的一系列相关语句可以观察到不同的更新。 REPEATABLE READ 和 SERIALIZABLE 看到 UPDATE 就好像它们是原子的和一致的。
想象两个会话。会话 A 具有 SERIALIZABLE 隔离级别,并且在具有 1000 行的表中执行:UPDATE tokens SET tokens = tokens + 1。
SELECT sum(tokens) FROM tokens → 此选择可以看到部分更新(即:某些行已更新而其他行未更新)。SELECT sum(tokens) FROM tokens → 此选择无法看到部分更新,因此它看到 UPDATE 就好像它是原子的。SELECT sum(tokens) FROM tokens WHERE id BETWEEN 1 AND 100; SELECT sum(tokens) FROM tokens WHERE id BETWEEN 501 AND 600,然后一些程序逻辑将这两个值相加 → 这些 SELECT 可以看到不同的 MVCC 快照 → 不同的更新,SELECT sum(tokens) FROM tokens WHERE id BETWEEN 1 AND 100; SELECT sum(tokens) FROM tokens WHERE id BETWEEN 501 AND 600,然后某些程序逻辑将这两个值相加 → 这些 SELECT 无法看到不同的 MVCC 快照 → 他们看到相同的更新,【讨论】: