在数据库的操作中,我们最常用的就是增删改查(CURD)。但在多用户并发的场景下,如果简单的CURD不加控制,会发生什么?
想象一个火车站售票系统:
-
当前票数: 1张。
-
客户端A: 检查发现还有1张票,准备下单。
-
客户端B: 在同一时刻也检查了票数,发现还有1张,也准备下单。
-
结果: A和B都买到了票,数据库票数变成-1。这就是典型的"超卖"问题。
为了解决这类并发导致的数据不一致问题,MySQL引入了------事务(Transaction)。
一、 什么是事务?
事务是一组DML(数据操作语言)语句的集合。在逻辑上,这些语句具有强相关性。
事务内的SQL语句要么全部执行成功,要么全部执行失败。
事务有两种类型:
1)当 autocommit = ON, 一个单独的SQL语句就是一个事务
比如select *from Roles;
2)由begin开始,commit结束
begin;
savepoint s1;
...
savepoint s2;
...
rollback;
commit;
二、 事务的核心特性:ACID原则
一个完整的事务必须满足四个属性,简称ACID。
1. 原子性(Atomicity)
-
定义: 事务是不可分割的最小工作单元。
-
核心逻辑: 事务中的所有操作要么全部完成,要么全部不完成。
-
实现机制: 如果在执行过程中发生错误,数据库会进行回滚(Rollback),将数据恢复到事务开始前的状态,仿佛这个事务从未发生过一样。
2. 一致性(Consistency)
-
定义: 事务执行前后,数据库的完整性没有被破坏。
-
核心逻辑: 写入的数据必须完全符合所有的预设规则(如约束、触发器等)。一致性其实是原子性、隔离性和持久性共同追求的最终目标。
3. 隔离性(Isolation)
-
定义: 数据库允许多个并发事务同时对数据进行读写。隔离性可以防止多个事务交叉执行时导致数据不一致。
-
隔离级别: 为了平衡性能与安全,MySQL提供了四种隔离级别:
-
读未提交(Read Uncommitted)
-
读提交(Read Committed)------大部分数据库默认级别
-
可重复读(Repeatable Read)------ MySQL默认级别
-
串行化(Serializable)
-
4. 持久性(Durability)
-
定义: 事务处理结束后,对数据的修改就是永久性的。
-
核心逻辑: 一旦事务提交,即使系统发生故障(如断电、宕机),修改过的数据也不会丢失,会被刷新到磁盘中。
三、 事务的版本支持
需要注意的是,并不是所有的MySQL存储引擎都支持事务。
-
InnoDB: 支持事务,是目前最常用的默认引擎。
-
MyISAM: 不支持事务。
四、 事务的提交方式与基本操作
MySQL默认是**自动提交(autocommit)**的。即每执行一条DML语句,MySQL就会自动帮你执行一次 COMMIT。
核心操作指令:
-
开启事务: BEGIN 或 START TRANSACTION;
-
设置保存点: SAVEPOINT 点名称; (就像单机游戏的"存盘点")
-
回滚到保存点: ROLLBACK TO 点名称;
-
全部回滚: ROLLBACK; (彻底撤销本次事务所有操作)
-
提交事务: COMMIT; (正式将改动持久化到磁盘)
五、 并发带来的三个"典型问题"
在多事务并发执行时,如果不进行隔离,会产生以下三种现象:
-
脏读(Dirty Read): 事务A读到了事务B尚未提交的数据。如果事务B最后回滚了,A读到的就是无效的"脏数据"。
-
不可重复读(Non-repeatable Read): 事务A在同一个事务内多次读取同一条数据 ,结果却不一样 (因为期间事务B修改并提交了该数据)。
-
幻读(Phantom Read): 事务A在同一个事务内多次按某个条件查询,结果发现记录数变多了(因为期间事务B插入并提交了新记录)。
知晓了这三个问题,我们来看看四大隔离级别。
六、四大隔离级别(读-写)
为了解决上述问题,SQL标准定义了四种隔离级别。MySQL通过这些级别,在"性能"与"安全性"之间寻求平衡。
**数据库并发的场景有三种:**读-读,读-写,写-写
1.读-读:不存在任何问题,也不需要并发控制
2.读-写 :有线程安全问题,可能会造成事务隔离性问题,可能遇到脏读,幻读,不可重复读3.写-写 :有线程安全问题,可能会存在更新丢失问题,比如第一类更新丢失,第二类更新丢失(后面补充)
这里先用读-写场景来介绍四种隔离级别。
1. 读未提交(Read Uncommitted)
特点: 最低级别,没有任何隔离性。
现象: 会产生脏读、不可重复读、幻读。
评价: 性能最高,但安全性极差,生产环境基本禁用。
2. 读提交(Read Committed, RC)
-
特点: 一个事务只能读到其他事务已经提交的数据。
-
现象: 解决了脏读,但存在不可重复读和幻读。
-
评价: 许多主流数据库(如Oracle, SQL Server)的默认隔离级别。

3. 可重复读(Repeatable Read, RR)
-
特点: 保证在同一个事务内,多次读取同一条记录的结果是一致的。
-
现象: 解决了脏读、不可重复读、幻读。( 理论上RR仍存在幻读,但MySQL的InnoDB引擎通过Next-Key Lock(间隙锁)在很大程度上解决了幻读问题。)
-
评价: MySQL的默认隔离级别,兼顾了性能与数据一致性。
防止不可重复读:

防止幻读:

4.串行化(Serializable)
-
特点: 最高的隔离级别。所有事务按顺序排队执行。
-
现象: 解决所有并发问题(脏读、不可重复读、幻读)。
-
评价: 它会对读取的每一行数据都加锁,会导致大量的超时和锁竞争,性能极低,除非对数据一致性有极端严格的要求,否则不使用。

可以看到,阻塞的时候,mysql不会有输出,也不会让你执行下一步操作。
总结:

