一.数据库事务
何为数据库事务( transaction)?事务是指访问并可能操作各种数据项的一个数据库操作序列,这些操作要么全部执行,要么全部不执行,是一个不可分割的工作单位。事务由事务开始与事务结束之间执行的全部数据库操作组成。
数据库管理系统(DBMS)在写入或更新资料的过程中,为保证事务(transaction)是正确可靠的,所必须具备的四个特性:原子性(atomicity,或称不可分割性)、一致性(consistency)、隔离性(isolation,又称独立性)、持久性(durability)
二.ACID(事务处理的标准特性)
-
原子性(Atomicity)
一个事务(transaction)中的所有操作,要么全部完成,要么全部不完成,不会结束在中间某个环节。事务在执行过程中发生错误,会被恢复(Rollback)到事务开始前的状态,就像这个事务从来没有执行过一样。
2. 一致性(Consistency)
在事务开始之前和事务结束以后,数据库的完整性没有被破坏。且数据库中的数据始终都是保持一致的。
3. 隔离性(Isolation)
通常来说一个事务所做的修改在提交以前,对其他事务是不可见的。但是可以设置事务的隔离级别,来觉得这个不可见是否被允许。事务隔离分为不同级别,包括读未提交(Read uncommitted)、读提交(read committed)、可重复读(repeatable read)和串行化(Serializable)
4. 持久性(Durability)
事务处理结束后,对数据的修改就是永久的,即便系统故障也不会丢失。
三.事务的隔离级别
在SQL标准中定义了四种隔离级别,每一种级别都规定了一个事务中所做的修改,哪些在事务内和事务之间是可见的、哪些是不可见的。较低级别的隔离通常可以执行更高的并发,系统开销也更低。其各级别的特性入下图:
- 读未提交-Read uncommitted
- 读已提交-Read committed
- 可重复读-Repeatable read–MySQL
- 序列化-Serializable
注意:mysql的InnoDB的可重复读,解决了幻读的问题。文档如下:
”可重复读“隔离级别下MySQL是如何解决幻读问题的-CSDN博客
1.理解脏读、不可重复读、幻读
如上图所示,不同的隔离级别,对多个事务读取的数据而言,会造成各种不同的影响。其主要为表现为:脏读、不可重复读、幻读。其具体解释如下。
脏读:A事务读取到了B事务已添加或修改但还未提交的数据,如果B事务后期回滚了,那么A事务就读到了脏数据。
不可重复读: 同一个事务中,对于同一数据,执行完全相同的select语句时可能看到不一样的结果。
幻读:幻读,并不是说两次读取获取的结果集不同,幻读侧重的方面是某一次的 select 操作得到的结果所表征的数据状态无法支撑后续的业务操作。更为具体一些:select 某记录是否存在,不存在,准备插入此记录,但执行 insert 时发现此记录已存在,无法插入,此时就发生了幻读。幻读参考文档:MySQL幻读 - 简书,滑动验证页面。
2.事务的隔离级别测试。
测试首先要设置数据库的个理级别,隔离级别分为全局和当前事务两种,设置方法如下:
设置事务全局隔离级别:set global transaction isolation level read UNCOMMITTED;
设置事务当前会话隔离级别:set session transaction isolation level read UNCOMMITTED;
查看当前隔离级别如下:
select @@transaction_isolation;
show variables like 'transaction_isolation';
a.读未提交(READ-UNCOMMITTED)
该隔离级别最低会产生脏读、不可重复读、幻读。其中脏读测试如下。
b.读已提交(READ-COMMITTED)
该隔离级别不会产生脏读(a事务未提交的数据,b事务读不到);但是会产生不可重复读、幻读。其中不可重复读测试如下。
幻读测试如下:
如图。发现A事务第一次读,和第二次读不一样。就发生了幻读。或者在事务2里面去做删除张三。这个时候事务A第一次读的时候有张三的数据,第二次读就会没有张三。事务A会产生幻觉。
c. 可重复读(Repeatable-Read)
该隔离级别不会产生脏读(a事务未提交的数据,b事务读不到);不会产生不可重复读、但是会产生幻读(通过间隙锁解决幻读,MVCC)。其中不会产生不可重复读测试如下。
不会产生幻读测试如下:
1.快照读(select * from test )测试,看执行情况()。
快照读是通过MVCC原理解决的幻读,测试如下:
2.当前读(selectd *from test for update )测试,看执行情况。
当前读是通过间隙锁解决幻读,测试如下:
由图可知。数据库里数据(1,2,3,10)语句select * from tb_isolation_level where id >=10 for update ;会对10以后的间隙枷锁。3 -10 这个间隙不会加锁,所以insert ID= 6的时候不会阻塞,而ID=10 的数据 就会阻塞直至A事务提交。
d.序列化-Serializable
(同表同行数据 锁定)
(同表不同行数据 也是能读不能修改)
(同一行数据操作)
(两行数据操作)
总结:
mysql 的InnoDB,在隔离级别为:可重复读(Repeatable read)时,不会产生幻读(通过间隙锁解决了幻读问题。)