vlambda博客
学习文章列表

一文入门mysql事务隔离级别

    在重温mysql事务的时候在网上看了很多博客,做了以下总结,画了一些图方便理解。

    新人第一次发文,欢迎批评指正。

本文阅读时间约8分钟


一、事务

        作为单个逻辑单元执行一系列操作,要么完全执行,要么完全不执行。事务处理可以确保除非事务性单元内的所有操作都成功完成,否则不会永久更新面向数据的资源。

事务有四个属性,称为ACID属性:

1、原子性(Atomicity):事务是一个原子单位,要么全部执行,要么全部不执行

2、一致性(Consistent):事务的开始和结束,数据都必须保持一致状态。

3、隔离性(isolation):数据库系统提供隔离机制,保证并发事务之间是互相不干扰的。也就意味着事务处理过程中的中间状态对其他的事务是透明的。

4、持久性(Durable):事务完成之后,对数据的修改是永久性的,即使出现系统故障也能够保持

    

        事务是一系列SQL语句的集合,mysql中只有使用了Innodb 数据库引擎的数据库或表才支持事务。

二、数据库读现象

    ACID属性里面有一个是隔离级别,不同的级别会对并发的性能起不同的影响作用。

    简单一句话概括就是,越随便,越支持并发。

 

    日常业务中主要出现下面的几种读取数据的现象

2.1、脏读

    事务T1修改某个字段的值,然后事务T2读取该值,此后T1撤销了对该字段的更新,或者更新成另外的值才commit到数据库中,这样T2读取的数据是无效的或者错误的。导致T2依据脏数据所做的操作也是错误的。

一文入门mysql事务隔离级别



2.2、不可重复读

    在数据库访问中,一个事务范围内的两次相同的查询却返回了不同的数据。

事务T1读取某一数据,事务T2读取并修改了该数据,T1为了对读取值进行验证而重新读取,却发现得到了不同的结果。


一文入门mysql事务隔离级别



2.3、幻读

       幻读其实有很多种情况,直接的理解就是,“我刚刚明明没看到这个数据,现在怎么出现了?”像中月读一样。


    比如说:T1查了一下某张表的行数,T2也查了一下并插入了一条新数据。导致T1复查的时候感觉自己见了鬼。

    幻读和不可重读有一点像,但主要区别是

        不可重复读重点在于update和delete,而幻读的重点在于insert



三、事务前置知识——锁


3.1、表锁和行锁

    表锁和行锁锁的粒度不一样,表锁锁住的是一整张表,行锁锁住的是表中的一行数据,行锁是开销最大的锁策略,表锁是开销最小的锁策略。

3.2、共享锁和排他锁
    共享锁又称读锁( S 锁),一个事务获取了共享锁,其他事务可以获取共享锁,不能获取排他锁,其他事务可以进行读操作,不能进行写操作。
 
    排他锁又称写锁( X 锁),如果事务 T 对数据 A 加上排他锁后,则其他事务不能再对 A 加任何类型的锁(读和写啥都不可)。获准排他锁的事务既能读数据,又能修改数据。

  
四、事务的隔离级别

4.1未提交读
    事务的最低隔离级别,在这种隔离级别下,一个事务可以读取另外一个事务未提交的数据。
    锁实现原理:
    事务T在读数据的时候并未对数据进行加锁,事务T在修改数据的时候对数据增加行级共享锁。
    T1在读取数据时,T2可以对相同数据进行读取、修改。因为T1没有进行任何锁操作;当T2对记录进行修改时,T1再次读取数据可以读取到T2修改后的数据。因为T2对数据进行修改只增加了行级共享锁,T1可以再增加共享读锁进行数据读取(尽管T2没有提交事务)
如上所述,这种隔离级别,会导致脏读现象

4.2已提交读
    在一个事务修改数据过程中,如果事务没有进行提交,其他事务不能读取该数据

    锁实现原理:
    事务T在读取数据时增加行级共享锁,读取一旦结束,立即释放;事务T在修改数据时增加行级排他锁,直到事务结束才释放。

    如上所述,这种隔离级别,解决了脏读问题,但是 不能解决不可重复读现象。
因为行级共享锁在读完就马上释放了,一个事务中不能保证读两次的数据是一样的。
除非。。。。

4.3、可重复读

    锁实现原理:
        事务T在数据读取时,必须增加行级共享锁,直到事务结束;事务T在修改数据过程中,必须增加行级排他锁,直到事务结束。
强调是 一整个事务内都不释放锁
    T1在读取数据的过程中,T2也可以对相同数据进行读取,但是不能进行修改(T1增加的是共享锁,T2也可以增加共享锁,但是不能增加排他锁)。直到T1事务结束后,才会释放共享锁,这时T2才可以增加排他锁,对数据进行修改。
    如上所述,这种隔离级别,解决了不可重复读现象,但是这种隔离级别解决不了 幻读的问题
    T1进行查询,读取了10条记录,并对十条记录增加了行级锁,此时T2是无法对这10行数据进行修改操作的,但是由于没有表级锁,它可以增加一条满足T1查询条件的记录。随后T1在进行查询时,会发现虽然10条记录没有改变, 但是突然多了一条记录。

4.4、序列化

    产生幻读是由于没有进行范围查询时没有增加范围锁。
锁实现原理:

    事务T在读取数据时,必须先增加表级共享锁,直到事务结束才释放;事务T在修改数据时,必须先增加表级排他锁,直到事务结束才释放。

       T1在读取A表时,增加了表级共享锁,此时T2也可以读取A表,但是不能进行任何数据的修改,直到T1事务结束。随后T2可以增加对A表的表级排他锁,此时T1不能读取A表中的任何数据,更不能进行修改。
如上所述,可序列化解决了脏读、不可重复读、幻读等读现象,但是隔离级别越来越高的同时,在并发性上也就越来越低。在高并发情况下会导致很多事务阻塞。


    下次总结一波Tomcat并发处理请求吧......