注:begin或start transaction并不是一个事务的起点,而是在执行它们之后的第一个操作InnoDB表的语句,事务才真正开始。start transaction with consistent snapshot命令可以马上启动一个事务。
1、隔离级别
1.1、基本概念
读未提交
读提交
可重复读
串行化
1.2、小测试一
理解了隔离级别的基本概念后,我们做个小测试,看看是不是真的理解了,下面两个会话按顺序执行,最后在各个隔离级别下的V1、V2值各为多少呢?启动事务 | |
查询得到值1 | |
启动事务 | |
把值1更新成值2 | |
查询得到值V1 | |
提交事务 | |
查询得到值V2 | |
提交事务 | |
查询得到值V3 |
读未提交
可以读取到其他事务未提交的值,所以V1读取到了sessionB未提交的更改,值为2。
读提交
不能读取到其他事务未提交的值,所以V1的值为1,当查询V2时,sessionB已经提交了,这时读取到的V2为2。
可重复读
查询得到的值为事务启动时的值,所以V1和V2值都为1。
串行化
时,sessionA启动事务后,sessionB会被卡住,直至sessionA的事务提交后才执行,所以V1和V2都是1,V3查询时sessionB已经提交事务,所以V3的值为2。
读未提交 | 2 | 2 | 2 |
读提交 | 1 | 2 | 2 |
可重复读 | 1 | 1 | 2 |
串行化 | 1 | 1 | 2 |
1.3、小测试二
上面的小测试一加深了我们对事务隔离级别的了解,下面我们针对可重复读隔离级别下对小测试一进行修改再加深理解。例子如下:
启动事务 | |
查询得V值为1 | |
启动事务 | |
set V=V+1 | |
查询得到值V1 | |
提交事务 | |
set V=V+1 | |
查询得到值V2 | |
提交事务 | |
查询得到值V3 |
小测试一可重复读隔离级别下V1、V2的值都为1,V3的值为2。根据小测试一的思路,你可能会得出小测试二的结果为V1为1,V2为2,那么V3是多少呢?
其实正确的答案是V1为1,V2为3,V3为3。如果sessionA中的set V=V+1是set V=1+1的话,这样就丢失了sessionB更新的操作,使数据不正确,这时因为sessionB提交了,所以sessionA中的更新同一个值为当前读
,为set V=2+1,所以V2为3。小测试一中读取的数据在概念中为一致性读
。
如果流程中把sessionB的提交事务放在sessionA的提交事务后面呢?这个时候sessionA的set V=V+1会被阻塞,直至sessionB的事务提交后才会执行,结果还是V1为1,V2为3,V3为3。
1 | 2 |
如上表格所示视图,行数据从1更新为2的过程对应视图view1到view2的过程。
读提交隔离级别下,事务启动时是view1视图,当sessionB发生更新数据后,视图view1会更新成视图view2,后续查询在view2上进行。
可重复读隔离级别下,事务启动时是view1视图,当sessionB发生更新数据后,事务还是照样读取view1视图。
可重复读隔离级别下,是怎么找到view1视图的呢?
其实这就是MVCC的功能了,事务在启动时会获得系统会分配一个按顺序递增的transaction id,然后事务在更新数据时会把这个transaction id 分配给这一行数据当做trx row_id,顺便记录undo log日志。比如上面sessionA事务在启动时拿到的transaction id为889,sessionB的transaction id为890,那么sessionB更新完后数据的trx row_id为890。在查询V2的值时,sessionA发现数据版本为890,当前自己事务id为889,所以利用undo log“回滚”显示出上一版本的数据,上一版本可以是889也可能是比889小的trx row_id,取值。
1.4、隔离级别解决脏读、不可重复读、幻读
声明一点,读未提交、读提交、可重复读、串行化隔离级别依次递增,隔离得越严实,效率就越低。
脏读
不可重复读
幻读
根据上述脏读、不可重复读、幻读的概念与隔离级别能做到的,我可以得出以下关系:
读未提交 | 可能 | 可能 | 可能 |
读提交 | 不可能 | 可能 | 可能 |
可重复读 | 不可能 | 不可能 | 可能 |
串行化 | 不可能 | 不可能 | 不可能 |
2、ACID
A.Atomicity.原子性
原子性通过undo log实现,undo log记录了回滚信息,当事务失败或进行rollback时,就会根据信息回滚到操作前的样子。
当delete时,undo log会相应记录被删除数据的信息,当发生回滚时,进行insert操作。
当update时,undo log会记录更新操作的信息,当发生回滚时,进行update操作。
当insert时,undo log会记录对应的主键,当发生回滚时,进行delete操作。
C.Consistency.一致性
一致性是通过原子性、隔离性、持久性来保证的。所以只有保证了AID特性,才能保证C特性。
I.Isolation.隔离性
隔离性通过MVCC实现,具体实现可以参考上面中的小测试逻辑。
D.Durability.持久性
持久性通过redo log实现,MySQL中有个WAL的逻辑,就是编辑数据时,会先更新redo log日志,再更新内存,最后再写磁盘。写redo log日志是一个非常快的操作,而更新完内存后,写进磁盘是很忙的。当还没写进磁盘时发生宕机等,MySQL重启后会自动去对比redo log日志与磁盘内容,把未刷进磁盘的数据刷进磁盘中,从而保证了数据的持久性。
3、扩展知识
undo log
MVCC
乐观锁
悲观锁