mysql-事务隔离级别

   数据库    数据库  mysql

事务ACID特性

* 原子性(Atomicity)

一个事物内的所有操作视为一个不可分割的操作,事务内所有操要么全执行成功要么全失败
例如:一个事务内A给B转账,先从A账户中扣钱,然后向B账户中加对应的钱数,这两次数据库操作要么全成功要么全失败,不能某个操作成功了,其他的失败了

* 一致性(Consistency)

一个事务可以封装状态改变(除非它是一个只读的)。事务必须始终保持系统处于一致的状态,不管在任何给定的时间并发事务有多少(摘自百度)
例如:一共有2个账户,这些账户的总余额为100,无论如何进行并发操作最终这2个账户的余额的和必须为100

* 隔离性(Isolation)

隔离状态执行事务,使它们好像是系统在给定时间内执行的唯一操作

  • MVCC(Mutil-Version Concurrency Control) 多版本并发控制

    如果没有MVCC,当想要读取的数据被其他事务用排它锁锁住时,只能互斥等待;而这时MVCC可以通过提供历史版本从而实现读取被锁的数据的历史版本,从而避免了互斥等待。

    • Shared Locks(共享锁/S锁)

      若事务T对数据对象A加上S锁,则事务T只能读A;其他事务只能再对A加S锁,而不能加X锁,直到T释放A上的S锁。这就保证了其他事务可以读A,但在T释放A上的S锁之前不能对A做任何修改。

    • Exclusive Locks(排它锁/X锁)

      若事务T对数据对象A加上X锁,则只允许T读取和修改A,其它任何事务都不能再对A加任何类型的锁,直到T释放A上的锁。它防止任何其它事务获取资源上的锁,直到在事务的末尾将资源上的原始锁释放为止。在更新操作(INSERT、UPDATE 或 DELETE)过程中始终应用排它锁。

      注意:排他锁会阻止其它事务再对其锁定的数据加读或写的锁,但是不加锁的就没办法控制了。

    • Record Locks(行锁)

      是加在索引行(对!是索引行!不是数据行!)上的锁。比如select * from user where id=1 and id=10 for update,就会在id=1和id=10的索引行上加Record Lock。

    • Gap Locks(间隙锁)

      间隙锁,它会锁住两个索引之间的区域。比如select * from user where id>1 and id<10 for update,就会在id为(1,10)的索引区间上加Gap Lock。

    • Next-Key Locks(间隙锁)

      也叫间隙锁,它是Record Lock + Gap Lock形成的一个闭区间锁。比如select * from user where id>=1 and id<=10 for update,就会在id为[1,10]的索引闭区间上加Next-Key Lock。

      组合起来就有,行级共享锁,表级共享锁,行级排它锁,表级排它锁。

  • 加锁

    • insert、delete和update都是会加排它锁(Exclusive Locks)
    • select只有显式声明才会加锁
      • select: 即最常用的查询,是不加任何锁的
      • select … lock in share mode: 会加共享锁(Shared Locks)
      • select … for update: 会加排它锁

* 持久性(Durability)

在事务完成以后,该事务对数据库所作的更改便持久的保存在数据库之中,并不会被回滚

事务隔离级别

完全隔离是不现实的,因为完全隔离会使事务串行化,严重影响并发性能,所以引入隔离级别来控制并发访问

MySQl支持4中隔离级别

隔离级别 描述
读未提交(read uncommitted) 一个事务可以读其他事务未提交的数据
读已提交(read committed) 一个事务只能读其他事务已提交的数据
可重复读(repeatable read) 一个事务内多次读同一数据必须一致(MySQL默认隔离级别)
串行化(serializable) 事务串行化,同一个表同时只能有一个事务进行操作

并发引发问题

  • 脏读

    A事务读取了B事务未提交的数据并在此基础上进行操作,结果B事务回滚了,那么A所进行的操作就是有问题的

  • 不可重复读

    不可重复读指同一事务中两次读取的数据不一致,A事务读取了一条数据,B事务修改了数据并且提交了,A事务又读了此条数据结果与上一读取的数据不一致

  • 幻读

    事务A统计了数据量,事务B添加了N条记录,事务B又查了一次,结果两次结果数量不一致

隔离级别对应问题

  • 隔离级别越往下并发效率越低,可重复读行级锁,串行化表级锁(x:可能 √:不可能)
级别\问题 脏读 不可重复读 幻读 实现方式
读未提交(read uncommitted) x x x 读没有控制,写加排他锁
读已提交(read committed) x x 快照读:读MVCC,写加排他锁 当前读:读加行锁,写加排它锁
可重复读(repeatable read) x 读MVCC,写加排他锁 当前读:读加间隙锁,写加排它锁
串行化(serializable) 读加共享锁,写加排他锁
  • 在读未提交、读已提交、可重复读的隔离级别中:
    • 两个读的事务,可并发;
    • 一读、一写的事务,可并发;(因为只有写加锁)
    • 两个写的事务,不可以并发。(以内都加了排他锁)

总结

只有InnoDB引擎支持事务并且支持行级锁,MyISAM引擎并不支持事务且仅支持表级锁
InnoDB适合频繁update业务场景(交易系统),MyISAM适用于大量select、insert业务场景(日志类系统)
处理数据库并发问题并非只能依靠数据来处理,可以结合代码进行合理的加锁,例如依靠外部redis/zookeeper做分布式锁

  1. 事务ACID特性
    1. * 原子性(Atomicity)
    2. * 一致性(Consistency)
    3. * 隔离性(Isolation)
    4. * 持久性(Durability)
  2. 事务隔离级别
  3. 并发引发问题
  4. 隔离级别对应问题
  5. 总结
sharding jdbc
mysql索引失效