zoukankan      html  css  js  c++  java
  • mysql事物隔离级别

    mysql实现了四种隔离级别

    Read Uncommitted(未提交读)

           在该隔离级别,所有事务都可以看到其他未提交事务的执行结果。本隔离级别很少用于实际应用,因为它的性能也不比其他级别好多少。读取未提交的数据,也被称之为脏读(Dirty Read)。

    Read Committed(不可重复读)

           这是大多数数据库系统的默认隔离级别(但不是MySQL默认的)。它满足了隔离的简单定义:一个事务只能看见已经提交事务所做的改变。这种隔离级别 也支持所谓的不可重复读(Nonrepeatable Read),因为同一事务的其他实例在该实例处理其间可能会有新的commit,所以同一select可能返回不同结果。(一个事物多次读取的结果可能不一样)。也叫提交读。

    Repeatable Read(可重复读)

           这是MySQL的默认事务隔离级别,它确保同一事务的多个实例在并发读取数据时,会看到同样的数据行(mysql用快照解决该问题)。不过理论上,这会导致另一个棘手的问题:幻读 (Phantom Read)。简单的说,幻读指当用户读取某一范围的数据行时,另一个事务又在该范围内插入了新行,当用户再读取该范围的数据行时,会发现有新的“幻影” 行(mysql用间隙锁解决该问题)。InnoDB和Falcon存储引擎通过多版本并发控制(MVCC,Multiversion Concurrency Control)机制解决了该问题。(一个事物多次读取的结果一样)。

    Serializable(可串行化) 
           这是最高的隔离级别,它通过强制事务排序,使之不可能相互冲突,从而解决幻读问题。简言之,它是在每个读的数据行上加上共享锁。在这个级别,可能导致大量的超时现象和锁竞争。

    -------------------------------------------------------------------------------------------------------------------------------------------------

    Repeatable Read隔离级别衍生问题总结

    幻读:一个事务在操作过程中!有别的事务对此数据集进行了修改并提交,但这些操作第一个事务读不到,等到这个事务提交的时候,便有可能引起明明插入的数据没有查询到,但却出现插入重复的错误!

    不可重复读与幻读的区别

    不可重复读是能读到其它事务已经提交的数据,幻读是读不到其它事务已提交的数据!

    间隙锁:间隙锁主要用来防止幻读,用在repeatable-read隔离级别下,指的是当对数据进行条件,范围检索时,对其范围内也许并存在的值进行加锁!

    ---------------------------------------

    比如where id <8 lock in share mode,则对8以下的值都加间隙锁,

    select max(id) ........lock in share mode,则会对max(id)以上的并不存在值加间隙锁!  

    select * from e where id=20 lock in share mode 则只会对id=20加锁!(此时可能只是普通的共享锁了)

    select * from e lock in share mode; 则对整个e加上间隙表锁!

    幻读案例:有个表(id字段为唯一约束)每次插入前需查询这字段的最大值,然后再取最大值+1插入!

    事务1:                                                                            事务2:

    select max(id) from e;                                                      insert into e values (11)

    10                                                                                   commit;

    insert into e values (11)

    commit;

    ERROR 1062 (23000): Duplicate entry ‘11‘ for key ‘id‘

    在上述事务1中明明查询最大值为10,但插入最大值+1的时候却报错!

    解决方案:利用mysql间隙锁

    事务1:                                                                           事务2:

    select max(id) from e lock in share mode;  

    (此时会对id为10以上的所有不存在的值加间隙锁)                   

    10                                                                                  insert into e values (11);

    insert into e values (11)                                                   commit;  此时提交会一处于等待状态,

    commit;

    ---------------------------------------

    幻读问题解决,但是上面的例子中,会导致上面的插入语句等待。

    间隙锁是innodb中行锁的一种, 但是这种锁锁住的却不止一行数据,他锁住的是多行,是一个数据范围。间隙锁的主要作用是为了防止出现幻读,但是它会把锁定范围扩大,有时候也会给我们带来麻烦,我们就遇到了。 在数据库参数中, 控制间隙锁的参数是:innodb_locks_unsafe_for_binlog, 这个参数默认值是OFF, 也就是启用间隙锁, 他是一个bool值, 当值为true时表示disable间隙锁。那为了防止间隙锁是不是直接将innodb_locaks_unsafe_for_binlog设置为true就可以了呢? 不一定!而且这个参数会影响到主从复制及灾难恢复, 这个方法还尚待商量。

    间隙锁的出现主要集中在同一个事务中先delete 后 insert的情况下, 当我们通过一个参数去删除一条记录的时候, 如果参数在数据库中存在, 那么这个时候产生的是普通行锁, 锁住这个记录, 然后删除, 然后释放锁。如果这条记录不存在,问题就来了, 数据库会扫描索引,发现这个记录不存在, 这个时候的delete语句获取到的就是一个间隙锁,然后数据库会向左扫描扫到第一个比给定参数小的值, 向右扫描扫描到第一个比给定参数大的值, 然后以此为界,构建一个区间, 锁住整个区间内的数据, 一个特别容易出现死锁的间隙锁诞生了。

    这种问题的解决办法:前面说了, 通过修改innodb_locaks_unsafe_for_binlog参数来取消间隙锁从而达到避免这种情况的死锁的方式尚待商量, 那就只有修改代码逻辑, 存在才删除,尽量不去删除不存在的记录。

  • 相关阅读:
    BGP--边界网关协议
    Paris Traceroute
    网站flash黑屏问题
    org.pentaho.di.ui.core.widget.PasswordTextVar
    java 金额计算,商业计算 double不精确问题 BigDecimal,Double保留两位小数方法
    spring mvc 利用匿名内部类构建返回json对象
    bootstrap3-typeahead 自动补全
    高德地图 省市区商圈数据
    小米wifi远程提交下载任务地址
    国外HTML网站模版(卖成品模版)
  • 原文地址:https://www.cnblogs.com/gauze/p/6029844.html
Copyright © 2011-2022 走看看