MySQL:事务详细

目录

一、什么是事务?

二、事务的四大基石:ACID特性

[1. 原子性(Atomicity)](#1. 原子性(Atomicity))

[2. 一致性(Consistency)](#2. 一致性(Consistency))

[3. 隔离性(Isolation)](#3. 隔离性(Isolation))

[4. 持久性(Durability)](#4. 持久性(Durability))

三、实战:如何在MySQL中使用事务?

[1. 确认存储引擎支持](#1. 确认存储引擎支持)

[2. 基本语法](#2. 基本语法)

[3. 实战演示:回滚 vs 提交](#3. 实战演示:回滚 vs 提交)

[4. 高级技巧:保存点(Savepoint)](#4. 高级技巧:保存点(Savepoint))

[5. 自动提交 vs 手动提交](#5. 自动提交 vs 手动提交)

四、事务隔离级别

[1. 四种隔离级别概览](#1. 四种隔离级别概览)

[2. 查看和设置隔离级别](#2. 查看和设置隔离级别)

[3. 三大并发问题详解](#3. 三大并发问题详解)

[🔴 问题一:脏读(Dirty Read)](#🔴 问题一:脏读(Dirty Read))

[🟡 问题二:不可重复读(Non-repeatable Read)](#🟡 问题二:不可重复读(Non-repeatable Read))

[🟢 问题三:幻读(Phantom Read)](#🟢 问题三:幻读(Phantom Read))

[4. 串行化(SERIALIZABLE)](#4. 串行化(SERIALIZABLE))

五、最佳实践与建议

[✅ 推荐做法](#✅ 推荐做法)

[❌ 避免陷阱](#❌ 避免陷阱)

一、什么是事务?

想象一下这样的场景:张三给李四转账100元。这个操作涉及两条SQL语句:

  1. 张三的账户余额减少100元
  2. 李四的账户余额增加100元

如果第一条执行成功,第二条却失败了,会发生什么?张三的钱扣了,李四却没收到,这显然不行!

事务(Transaction) 就是为了解决这个问题而生的。它将一组SQL语句打包成一个整体,要么全部成功,要么全部失败。在事务执行过程中,数据库会保证以下四点:

  • 转账前后总金额不变
  • 结果永久保存
  • 执行过程不受其他事务干扰
  • 不会出现"钱扣了但对方没收到"的中间状态

这正是事务的ACID特性在发挥作用。

二、事务的四大基石:ACID特性

1. 原子性(Atomicity)

"要么全做,要么全不做"

事务中的所有操作是一个不可分割的整体。如果执行过程中发生错误,整个事务会**回滚(Rollback)**到初始状态,就像从未执行过一样。

2. 一致性(Consistency)

"数据始终符合业务规则"

事务执行前后,数据库的完整性约束不被破坏。比如转账前后,两人的总金额必须保持2000元不变。

3. 隔离性(Isolation)

"各干各的,互不干扰"

多个并发事务同时操作时,彼此之间不会相互影响。数据库通过不同的隔离级别来平衡性能与安全性。

4. 持久性(Durability)

"一旦提交,永不丢失"

事务提交后,对数据的修改会永久写入存储介质,即使系统崩溃也不会丢失。

三、实战:如何在MySQL中使用事务?

1. 确认存储引擎支持

只有支持事务的存储引擎才能使用事务功能。在MySQL中,InnoDB是默认支持事务的引擎:

复制代码
SHOW ENGINES;

2. 基本语法

sql 复制代码
-- 开启事务
START TRANSACTION;  -- 或 BEGIN;

-- 执行一系列SQL操作
UPDATE bank_account SET balance = balance - 100 WHERE name = '张三';
UPDATE bank_account SET balance = balance + 100 WHERE name = '李四';

-- 提交事务(永久保存)
COMMIT;

-- 或者回滚事务(撤销所有操作)
ROLLBACK;

3. 实战演示:回滚 vs 提交

场景一:执行后回滚

sql 复制代码
START TRANSACTION;
UPDATE bank_account SET balance = balance - 100 WHERE name = '张三';
UPDATE bank_account SET balance = balance + 100 WHERE name = '李四';
-- 此时查询会发现余额已变
SELECT * FROM bank_account; 
-- 但执行回滚后
ROLLBACK;
-- 再次查询,数据恢复原状!

场景二:执行后提交

sql 复制代码
BEGIN;
UPDATE bank_account SET balance = balance - 100 WHERE name = '张三';
UPDATE bank_account SET balance = balance + 100 WHERE name = '李四';
COMMIT;
-- 提交后,修改永久生效,无法回滚

4. 高级技巧:保存点(Savepoint)

在长事务中,可以设置保存点实现部分回滚:

sql 复制代码
START TRANSACTION;
UPDATE bank_account SET balance = balance - 100 WHERE name = '张三';
SAVEPOINT point1;  -- 设置保存点

UPDATE bank_account SET balance = balance - 100 WHERE name = '张三';
SAVEPOINT point2;

INSERT INTO bank_account VALUES (NULL, '王五', 1000);

-- 回滚到point2,插入操作被撤销,但之前的更新保留
ROLLBACK TO point2;

-- 回滚到point1,第二次更新也被撤销
ROLLBACK TO point1;

-- 完全回滚
ROLLBACK;

5. 自动提交 vs 手动提交

MySQL默认开启自动提交(autocommit=ON),每条SQL都是一个独立事务。

sql 复制代码
-- 查看当前设置
SHOW VARIABLES LIKE 'autocommit';

-- 关闭自动提交,进入手动模式
SET AUTOCOMMIT = 0;  -- 或 SET AUTOCOMMIT = OFF;

-- 手动模式下,需要显式COMMIT或ROLLBACK
UPDATE bank_account SET balance = 500 WHERE id = 1;
COMMIT;  -- 必须手动提交才生效

⚠️ 注意 :一旦使用START TRANSACTION开启事务,无论autocommit设置如何,都必须手动COMMITROLLBACK

四、事务隔离级别

当多个用户同时操作数据库时,如何保证数据一致性?这就涉及到事务隔离级别。MySQL InnoDB引擎提供四种隔离级别,它们在性能和安全性之间做出不同取舍。

1. 四种隔离级别概览

隔离级别 脏读 不可重复读 幻读 性能
READ UNCOMMITTED 最高
READ COMMITTED 较高
REPEATABLE READ (默认) 大部分❌ 中等
SERIALIZABLE 最低

2. 查看和设置隔离级别

sql 复制代码
-- 查看当前会话隔离级别
SELECT @@SESSION.transaction_isolation;

-- 查看全局隔离级别
SELECT @@GLOBAL.transaction_isolation;

-- 设置会话级隔离级别(仅当前连接生效)
SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED;

-- 设置全局隔离级别(新连接生效)
SET GLOBAL TRANSACTION ISOLATION LEVEL REPEATABLE READ;

3. 三大并发问题详解

🔴 问题一:脏读(Dirty Read)

发生场景 :**READ UNCOMMITTED**级别

现象 :事务A读取了事务B未提交的数据,如果事务B随后回滚,事务A读到的就是"脏数据"。

重现过程

  1. 事务A插入一条记录但不提交
  2. 事务B读取到了这条未提交的记录
  3. 事务A回滚,记录消失
  4. 事务B读到的数据成了"幽灵"

💡 结论 :生产环境严禁使用READ UNCOMMITTED

🟡 问题二:不可重复读(Non-repeatable Read)

发生场景READ COMMITTED级别

现象:同一事务内,两次读取同一行数据,结果不一致(因为其他事务修改并提交了)。

重现过程

  1. 事务A第一次查询"王五"余额为2000
  2. 事务B将"王五"余额改为1000并提交
  3. 事务A再次查询,发现余额变成1000
  4. 同一事务内,相同查询得到不同结果!
🟢 问题三:幻读(Phantom Read)

发生场景REPEATABLE READ级别(理论上存在,InnoDB通过Next-Key锁大幅缓解)

现象:同一事务内,两次查询同一范围的数据,行数不一致(因为其他事务插入了新记录)。

重现过程

  1. 事务A查询所有余额>1000的记录,得到3条
  2. 事务B插入一条新记录并提交
  3. 事务A再次查询同一条件,得到4条
  4. 仿佛出现了"幻影"行!

MySQL的优化 :InnoDB引擎在REPEATABLE READ级别下使用Next-Key锁(记录锁+间隙锁),有效解决了大部分幻读问题。

4. 串行化(SERIALIZABLE)

最高隔离级别,所有事务串行执行,彻底解决并发问题,但性能代价极高,通常只用于对一致性要求极端严格的场景。

五、最佳实践与建议

✅ 推荐做法

  1. 默认使用REPEATABLE READ:MySQL的默认隔离级别,在安全性和性能间取得良好平衡
  2. 短事务原则:事务包含的SQL越少、执行时间越短越好
  3. 明确提交/回滚:不要依赖自动提交,显式控制事务边界
  4. 异常处理:在代码中捕获异常并及时回滚
  5. 避免长事务:长事务会占用锁资源,影响并发性能

❌ 避免陷阱

  1. 不要在事务中进行网络请求、文件IO等耗时操作
  2. 避免在事务中等待用户输入
  3. 不要随意降低隔离级别换取性能
  4. 警惕隐式提交(如DDL语句会自动提交当前事务)
相关推荐
qq_148115372 小时前
Python上下文管理器(with语句)的原理与实践
jvm·数据库·python
qwehjk20082 小时前
机器学习模型部署:将模型转化为Web API
jvm·数据库·python
Counter-Strike大牛2 小时前
SpringBoot项目调用数据库函数报错Result consisted of more than one row
数据库·spring boot·后端
沪漂阿龙2 小时前
深度解析SQL查询:从关联查询到子查询,一文掌握数据库核心技能
数据库·sql
吠品3 小时前
MySQL LEFT() 函数:精准截取字段前N位,掌握字符串处理核心
数据库·oracle
.生产的驴3 小时前
1Panel实战|SpringColud微服务部署生产环境一键部署Docker+Nacos+MySQL 数据定时备份 控制台 安全高效易维护
服务器·后端·mysql·spring cloud·docker·微服务·信息可视化
Meepo_haha3 小时前
【JOIN】关键字在MySql中的详细使用
数据库·mysql
-Da-3 小时前
【操作系统学习日记】并发编程中的竞态条件与同步机制:互斥锁与信号量
java·服务器·javascript·数据库·系统架构
Predestination王瀞潞3 小时前
Base Tools-Associate-Fifth:re库详解
数据库·mysql