【MySQL8】事务
一、事务简介
1. 什么是事务
事务是一组 DML 操作的集合,是不可分割的最小工作单元。 事务会将集合内所有操作作为整体向数据库提交 / 撤销,集合内操作要么同时全部成功,要么同时全部失败。
2. 事务默认规则
MySQL 默认自动提交事务:执行一条 DML 语句就自动提交一次事务。 如果业务中途出现异常,需要手动回滚事务,保证数据一致性。
3. 事务标准执行流程
plaintext
开启事务 → 执行步骤1 → 执行步骤2 → 执行步骤3 → 无异常提交事务 / 出现异常回滚事务二、事务实操:转账案例
1. 数据准备 SQL
sql
-- 创建账户表 create table account( id int auto_increment primary key comment '主键ID', name varchar(10) comment '姓名', money int comment '余额' ) comment '账户表'; -- 初始化测试数据:张三、李四各2000元 insert into account(id, name, money) VALUES (null,'张三',2000),(null,'李四',2000); -- 恢复测试数据(每次测试前重置余额) update account set money = 2000 where name = '张三' or name = '李四';2. 转账业务需求
张三给李四转账 1000 元,分 3 步:
- 查询张三账户余额
- 张三余额减少 1000
- 李四余额增加 1000
2.1 无事务控制(存在数据安全隐患)
如果第二步执行后程序抛出异常,第三条更新语句不会执行,会出现张三钱减少、李四钱未增加的数据错乱。
sql
-- 1. 查询张三账户余额 select * from account where name = '张三'; -- 2. 将张三账户余额-1000 update account set money = money - 1000 where name = '张三'; -- 模拟程序异常,中断代码执行 -- 程序抛出异常 -- 3. 将李四账户余额+1000(异常后不会执行) update account set money = money + 1000 where name = '李四';2.2 手动开启事务完整示例
sql
-- 开启事务 START TRANSACTION; -- 1. 查询张三账户余额 select * from account where name = '张三'; -- 2. 张三扣1000 update account set money = money - 1000 where name = '张三'; -- 模拟程序异常 -- 程序抛出异常 -- 3. 李四加1000 update account set money = money + 1000 where name = '李四'; -- 无异常则提交事务,永久生效 COMMIT; -- 出现异常则回滚事务,所有操作全部撤销 ROLLBACK;三、事务两种控制方式
方式 1:修改自动提交参数(@@autocommit)
- 查看当前自动提交状态
sql
SELECT @@autocommit; -- 返回1:开启自动提交(MySQL默认) -- 返回0:关闭自动提交- 关闭自动提交(后续 DML 需要手动 commit)
sql
SET @@autocommit = 0;- 手动提交 / 回滚
sql
COMMIT; -- 提交事务,数据永久保存 ROLLBACK;-- 回滚事务,撤销所有未提交操作方式 2:START TRANSACTION显式开启事务
推荐业务开发使用,仅当前代码块生效,不修改全局自动提交配置
sql
-- 开启事务 START TRANSACTION; -- 业务DML操作... COMMIT; -- 正常提交 ROLLBACK;-- 异常回滚四、事务四大特性 ACID
- 原子性(Atomicity)事务是不可分割的最小操作单元,内部操作要么全部成功,要么全部失败。
- 一致性(Consistency)事务执行前后,数据库整体数据约束保持一致(转账总金额不变)。
- 隔离性(Isolation)并发执行的多个事务之间互相隔离,互不干扰。
- 持久性(Durability)事务一旦执行
COMMIT提交,对数据的修改永久保存到磁盘,宕机也不会丢失;回滚则完全撤销修改。
五、并发事务三大问题
多事务同时操作同一张表时,会出现三类数据问题,由隔离级别控制解决:
- 脏读一个事务读到了另一个事务未提交的修改数据。若对方事务回滚,读到的数据就是无效脏数据。
- 不可重复读同一个事务内,两次读取同一行数据,中间被其他事务修改并提交,两次查询结果不一致。
- 幻读同一个事务内,按条件查询无数据,插入数据时报主键冲突;因为其他事务已插入同条件数据,像出现 “幻影” 行。
六、事务四大隔离级别
隔离级别从低到高,隔离性越强,并发性能越低,安全性越高。
表格
| 隔离级别 | 脏读 | 不可重复读 | 幻读 |
|---|---|---|---|
| READ UNCOMMITTED(读未提交) | 存在 | 存在 | 存在 |
| READ COMMITTED(读已提交) | 解决 | 存在 | 存在 |
| REPEATABLE READ(可重复读,MySQL 默认) | 解决 | 解决 | 存在 |
| SERIALIZABLE(串行化) | 解决 | 解决 | 解决 |
1. 查看当前事务隔离级别
sql
SELECT @@TRANSACTION_ISOLATION;2. 设置事务隔离级别语法
sql
-- SESSION:仅当前会话生效;GLOBAL:全局所有客户端永久生效 SET [SESSION|GLOBAL] TRANSACTION ISOLATION LEVEL {READ UNCOMMITTED | READ COMMITTED | REPEATABLE READ | SERIALIZABLE}3. 各隔离级别设置示例
sql
-- 1. 读未提交(允许脏读) set session transaction isolation level read uncommitted; -- 2. 读已提交(解决脏读,Oracle默认) set session transaction isolation level read committed; -- 3. 可重复读(MySQL InnoDB默认,解决脏读、不可重复读) set session transaction isolation level repeatable read; -- 4. 串行化(最高安全,性能最差,完全串行执行) set session transaction isolation level serializable;核心结论
事务隔离级别越高,数据并发安全性越强,但数据库并发性能越低,开发中一般使用默认REPEATABLE READ。
七、总结
- 事务是一组 DML 操作集合,核心目标:要么全部成功,要么全部失败,保证数据安全;
- 事务操作核心命令:
START TRANSACTION开启、COMMIT提交、ROLLBACK回滚; - 事务四大核心特性:原子性、一致性、隔离性、持久性(ACID);
- 并发事务三类问题:脏读、不可重复读、幻读;
- 四级隔离级别:读未提交、读已提交、可重复读、串行化,安全递增、性能递减。