数据库 READ_COMMITED 隔离,事务手动开启状态下, update t set a=a-1 where id=1 and a-1>=0 是否安全?

2018-07-30 19:37:10 +08:00
 h8nhope

RT,

id 是自增主键,自己在本地 begin work 的方式开启多个事务,分别执行上面这一条语句,那这条 sql 会有并发问题吗?


看网上很多人说这条语句是先查到 a 的值再去计算最后 update 掉的。然鹅自己试的结果似乎并没有出现值覆盖的问题- -。

即便是 READ_UNCOMMIT 隔离下,开三个事务:

事务 A 提交了 update 之后,虽然事务 B、事务 C 均可以查到 A 未提交的值; 事务 B、事务 C 分别提交自己的 update,等待行锁; A 手动提交,B、C 分别手动提交;

发现最后似乎也没有出现 B C 拿同一个值去 update 的现象,a 最后的值是减了 3 的


mysql 不怎么熟悉,所以这种事务内的 update 语句,是会先拿到行锁再去取值的么?还是说要怎么操作才能出现异常 case ?有没有大佬可以指教下?

2647 次点击
所在节点    MySQL
2 条回复
fmumu
2018-07-30 20:52:46 +08:00
update table set a=a-1 这个操作是原子性的,不会出现你想象的那种异常吧
metrxqin
2018-07-30 23:19:00 +08:00
官方文档特别提到这个行为:

Using READ COMMITTED has additional effects:

For UPDATE or DELETE statements, InnoDB holds locks only for rows that it updates or deletes. Record locks for nonmatching rows are released after MySQL has evaluated the WHERE condition. This greatly reduces the probability of deadlocks, but they can still happen.

For UPDATE statements, if a row is already locked, InnoDB performs a “ semi-consistent ” read, returning the latest committed version to MySQL so that MySQL can determine whether the row matches the WHERE condition of the UPDATE. If the row matches (must be updated), MySQL reads the row again and this time InnoDB either locks it or waits for a lock on it.

https://dev.mysql.com/doc/refman/5.5/en/innodb-transaction-isolation-levels.html

UPDATE 操作不会使用快照值,所以不会有覆盖更新的问题。

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/475453

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX