MySQL事务状态判断
前置
MySQL的默认隔离级别是: 可重复读(REPEATABLE READ)
可重复读隔离级别下,事务中的SELECT操作会看到快照数据,也就是事务开始时刻的数据状态。此隔离级别可以防止脏读和不可重复读,但可能会有幻读的问题出现。
问题描述
表结构
create table djj
(
name varchar(100) null,
account int null
);
表数据
在事务开始前,表djj
中有一条记录:
name | account |
---|---|
djj | 50 |
脚本A和脚本B
脚本A和脚本B都是对表djj
进行的操作。脚本A将账户余额更新为40,而脚本B将账户余额更新为60。
操作流程
按照给定的操作流程,两个事务交错执行,如下:
flowchart TD ATXStart[A.TX Start] --> BTXStart[B.TX Start] BTXStart --> Aa[A.a] Aa --> Ab[A.b] Ab --> Ba[B.a] Ba --> Bb[B.b] Bb --> Ac[A.c] Ac --> ATXCommit[A.TX Commit] ATXCommit --> Bc[B.c] Bc --> BTXCommit[B.TX Commit]- A.a : 查找到的结果是 50
- A.b : 成功执行更新,账户余额变更为40
- B.a : 查找到的结果是 50(因为B事务的快照是在A事务提交前的状态)
- B.b : 此时因为A事务尚未提交,B事务的更新操作会等待A事务释放行锁
- A.c : 此时的结果是40(A事务可以看到自己的更新)
- A.TX Commit: A事务提交,释放行锁
- B.b : 执行成功,账户余额更新为60(B事务现在可以获取先前被A事务持有的行锁)
- B.c : 结果为60(B事务在提交前看到的是自己的更新)
注意
- 在可重复读隔离级别下,读操作不会看到其他未提交事务的更改(防止脏读),但写操作会等待其他事务释放锁(行锁或表锁),然后写入最新的数据。
- 死锁通常发生在多个事务试图以不同的顺序锁定资源时,例如,当两个事务都试图更新同一行数据,或者在使用
SELECT FOR UPDATE
时。在这种情况下,MySQL会自动检测死锁并回滚一个事务来解决问题。