在数据库的操作中我们最常用的就是增删改查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默认级别串行化Serializable4. 持久性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不会有输出也不会让你执行下一步操作。总结