详解MySQL事务(transaction),用图直观解释了MySQL脏读、不可重复读、幻读的问题
事务
事务是一组操作的集合,会把所有操作作为一个整体去执行,要么同时成功,要么同时失败。
事务操作
- 查看/设置事务提交方式
SELECT @@autocommit; # 1为自动,0为手动
SET @@autocommit = 0; # 改手动提交
- 提交事务
COMMIT;
- 回滚事务
ROLLBACK;
- 开启事务
START TRANSACTION 或 BEGIN;
事务的四大特性(ACID)
- 原子性(Atomicity):事务是不可分割的最小操作单元,要么全部成功,要么全部失败。
- 一致性(Consistency):事务完成时,必须使所有的数据都保持一致状态。
- 隔离性(Isolation):数据库系统提供的隔离机制,保证事务在不受外部并发操作影响的独立环境下运行。
- 持久性(Durability):事务一旦提交或回滚,它对数据库中的数据的改变是永久的。
并发事务问题
- 脏读:一个事务读到另外一个事务还有没提交的数据。
- 不可重复读:一个事务先读取同一条记录,但两次读取的数据不同。
- 幻读:一个事务按照条件查询数据时,没有对应的数据行,但是在插入数据时,又发现这行数据已经存在。
事务的隔离级别
- Read uncommitted
- 可发生 脏读、不可重复读、幻读
- Read committed
- 可发生 不可重复读、幻读
- Repeatable Read(默认)
- 可发生 幻读
- Serializable
- 隔离级别最高,不会发生
# 查看事务隔离级别
SELECT @@TRANSACTION_ISOLATION;
# 设置事务隔离级别
SET [SESSION | GLOBAL] TRANSACTION ISOLATION LEVEL { READ UNCOMMITTED | READ COMMITTED | REPEATABLE READ | SERIALIZABLE }
隔离等级为Read uncommitted,发生脏读的例子
脏读:一个事务读到另外一个事务还有没提交的数据。
- 代码:
- 代码运行图及结果:
- 首先,设置事务隔离级别为Read uncommitted,并开启事务A和事务B
- 1.执行 事务A代码 查询张三余额,结果为2000
- 2.执行 事务B代码 修改张三余额,注意:并没有提交事务B
- 3.执行 事务A代码 查询张三余额,结果为1000
隔离等级为Read committed,发生不可重复读的例子
不可重复读:一个事务先读取同一条记录,但两次读取的数据不同。
-
代码:
-
代码运行图及结果:
- 首先,设置事务隔离级别为Read committed,并开启事务A和事务B
- 1.执行 事务A代码 查询张三余额,结果为1000
- 2.执行 事务B代码 修改张三余额,注意:并没有提交事务B
- 3.执行 事务A代码 查询张三余额,结果为1000
- 4.执行 事务B代码,commit
- 5.执行 事务A代码 查询张三余额,结果为0
隔离等级为Repeatable Read(默认),发生幻读的例子
-
幻读:一个事务按照条件查询数据时,没有对应的数据行,但是在插入数据时,又发现这行数据已经存在。
-
代码:
-
代码运行图及结果:
- 首先,设置事务隔离级别为Repeatable Read,并开启事务A和事务B
- 1.执行 事务A代码 查询id为3的数据,结果查询不到
- 2.执行 事务B代码 插入id为3的数据
- 3.执行 事务B代码 执行commit,结果提示成功插入
- 4.执行 事务A代码 插入id为3的数据,提示插入失败,已存在id为3的数据
- 5.执行 事务A代码 查询id为3的数据,结果查询不到,但是插入时却提示已存在id为3的数据
隔离等级为Serializable
隔离等级为Serializable,只允许一个事务进行操作,只有当这个执行的事务操作完成后,才会去执行其他事务,从而避免了 脏读、不可重复读、幻读 问题。