MySQL事务隔离级别
事务有 ACID 四个基本属性:原子性(Atomicity)、一致性(Consistency)、隔离性(Isolation)和持久性(Durability)
- 事务就是要保证一组数据库操作,要么全部成功,要么全部失败;
- 在 MySQL 中,事务支持是在引擎层实现的;
- 并不是所有引擎都支持事务,如 MyISAM 就不支持,InnoDB 就支持;
脏读
脏读(dirty read),简单来说,就是一个事务在处理过程中读取了另外一个事务未提交的数据。这种未提交的数据我们称之为脏数据。依据脏数据所做的操作肯能是不正确的。
不可重复读
不可重复读(non-repeatable read),是指一个事务范围内,多次查询某个数据,却得到不同的结果。在第一个事务中的两次读取数据之间,由于第二个事务的修改,第一个事务两次读到的数据可能就是不一样的。
脏读和不可重复读的区别:脏读是某一事务读取了另外一个事务未提交的数据,不可重复读是读取了其他事务提交的数据。
幻读
幻读(phantom read),是事务非独立执行时发生的一种现象。
例如事务 T1 对一个表中所有的行的某个数据项做了从“1”修改为“2”的操作,这时事务 T2 又对这个表中插入了一行数据项为“1”的数据,并且提交给数据库。而操作事务 T1 的用户如果再查看刚刚修改的数据发现还有1。
幻读和不可重复读:幻读和不可重复读都是读取了另一条已经提交的事务(这点就脏读不同),所不同的是不可重复读查询的都是同一个数据项,而幻读针对的是一批数据整体(比如数据的个数)。
事务的隔离级别
Serializable(串行化)
花费最高代价但最可靠的事务隔离级别。读写都加锁。事务 100% 隔离,可避免脏读、不可重复读、幻读的发生。
Repeatable read(可重复读,默认级别)
多次读取同一范围的数据会返回第一次查询的快照,即使其他事务对该数据做了更新修改。事务在执行期间看到的数据前后必须是一致的。
但如果这个事务在读取某个范围内的记录时,其他事务又在该范围内插入了新的记录,当之前的事务再次读取该范围的记录时,会产生幻行,这就是幻读。
可避免脏读、不可重复读的发生。但是可能会出现幻读
Read committed (读已提交)
保证一个事物提交后才能被另外一个事务读取。另外一个事务不能读取该事物未提交的数据。可避免脏读的发生,但是可能会造成不可重复读。
Read uncommitted (读未提交)
最低的事务隔离级别,一个事务还没提交时,它做的变更就能被别的事务看到。
事务隔离级别越高,越能保证数据的完整性和一致性,但是付出的代价却是并发执行效率的低下。
隔离级别的实现
事务的机制是通过视图(read-view)来实现的并发版本控制(MVCC),不同的事务隔离级别创建读视图的时间点不同。
-
可重复读是每个事务重建读视图,整个事务存在期间都用这个视图。
-
读已提交是每条 SQL 创建读视图,在每个 SQL 语句开始执行的时候创建的。隔离作用域仅限该条 SQL 语句。
-
读未提交是不创建,直接返回记录上的最新值
-
串行化隔离级别下直接用加锁的方式来避免并行访问。
这里的视图可以理解为数据副本,每次创建视图时,将当前已持久化的数据创建副本,后续直接从副本读取,从而达到数据隔离效果。