【MySQL】(12) 事务
一、事务的概念及应用场景
事务就是将一组 SQL 语句打包成一个整体,这个整体要么都执行成功,要么都失败。
假设张三有 1000 元,现张三需取出 100 元,若客户端1、2同时执行操作,造成取出 200,还剩 900 的情况,这不符合业务逻辑。
为了避免这些因并发操作的交叉执行、网络或服务器问题中断执行等产生的错误,同时让程序员更多地关注于业务实现、减少对于处理这些错误的精力消耗,主流的数据库都支持事务。
二、事务的 ACID 特性
- Atomicity(原子性):要么全部执行成功落盘,要么回滚全部执行失败。(实现:回滚日志会记录事务的执行状态)
- Consistency(一致性):事务执行前后,数据库符合业务逻辑和数据约束。
- Isolation(隔离性):控制并发执行互相干扰程度,指定不同隔离级别,平衡性能与一致性。
- Durability(持久性):事务提交后,修改的数据永久保存在存储介质,不受系统、断点影响。(先将重做日志写入磁盘,再将更新的数据页写入磁盘)
三、使用事务
1、查看存储引擎是否支持事务
查看默认使用的存储引擎 InnoDB 是否支持事务:
2、语法
- start transaction 或 begin:开始一个新事务。
- commit:提交事务,落盘。
- rollback:回滚,恢复到事务开始前的状态。
- savepoint savepoint_name:设置保存点。
- rollback to savepoint_name:回滚到保存点。
3、使用示例
3.1、开始事务,提交
3.2、开始事务,回滚
3.3、开始事务,回滚到保存点
4、自动/手动提交事务
其实每条 SQL 语句,例如增删改,都处于事务当中。只不过默认开启了自动提交事务,执行单句语句后会自动提交。
设置语法:
查看自动提交是否开启:
关闭自动提交,插入一条数据,在另一个客户端查询不到插入的数据:
手动提交:
注意:
- start transaction 后,必须 commit 或 rollback。
- 已提交的事务,不能回滚。
四、事务的隔离级别
1、事务的隔离性
并发执行时,每个客户端执行的 SQL 语句以事务为基本单位。当多个客户端对同一条数据进行修改时,事务的执行可能会互相影响。为了控制这种影响,MySQL 的 InnoDB 存储引擎定义了四种隔离级别,让事务之间具有隔离性。
2、读未提交(read uncommitted)
B 事务查询到 A 事务未提交的修改数据,这叫读未提交。如果 A 事务最后进行了回滚,那么 B 事务查询到的是错误的数据,这叫“脏读”。
3、读已提交(read committed)
事务 B 只能读取到事务 A 提交后的数据,未提交时数据对 B 不可见,这叫读已提交,避免了“脏读”。其它事务能修改 B 事务正在查询的数据,导致两次查询数据内容不一致,这叫“不可重复读”。
4、可重复读(repeatable read)(默认)
其它事务不能对 B 事务查询的数据进行修改,这叫可重复读。但是其它事务能插入 B 事务没有查询的新数据,导致 B 事务再次查询时读到结果集不一致,这叫“幻读”。
InnoDB 存储引擎中的 next-key 锁能锁住查询数据与之前数据之间的间隙,导致其它事务不能新增数据,解决了部分“幻读”。
5、串行化(serializable)
解决所有数据安全问题,事务之间是串行执行的。
6、总结
7、查询和设置隔离级别
7.1、查询隔离级别
作用域分为全局作用域(新建连接会读取全局参数)和会话作用域(只对当前客户端连接生效)。
7.2、设置隔离级别
语法:
# 方式一:
SET [GLOBAL|SESSION] TRANSACTION ISOLATION LEVEL 隔离级别|访问模式;level: {READ UNCOMMITTED # 读未提交
| READ COMMITTED # 读已提交
| REPEATABLE READ # 可重复读
| SERIALIZABLE
}access_mode: {READ WRITE # 可读写
| READ ONLY # 只能读
}# 方式二:
SET [GLOBAL|SESSION] TRANSACTION_ISOLATION = 'REPEATABLE-READ'; # 空格用-代替;# 方式三
SET [@@GLOBAL|@@SESSION].TRANSACTION_ISOLATION = 'REPEATABLE-READ'; # 空格用-代替;
实验:
8、问题重现
8.1、读未提交(脏读)
注:
- 如果 A 事务修改的是全局变量,需要重启 B 事务窗口才生效。
- 如果是修改当前会话,则两个会话都要修改才生效。
- 所有查询都是在同一个事务中。
8.2、读已提交(不可重复读)
8.3、可重复读(幻读)
可重复读:
幻读:由于可重复读隔离级别默认使用了 next-key 锁,为了重现幻读问题,使用读已提交。
事务的现实使用场景:电商平台,商品支付成功后,要更新订单状态、用户积分、物流记录,都包含在一个事务中。