Mysql:事务管理(上)
在数据库的操作中,我们最常用的就是增删改查(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不会有输出,也不会让你执行下一步操作。
总结:
