InnoDB关于事务、锁、MVCC专题

目录

  • 并发所带来的的问题
    • 脏写
    • 脏读
    • 不可重复读
    • 幻读
  • 事务
    • 事务的特性
    • 事务的四种隔离级别
    • 为什么要加锁
    • InnoDB的七种锁
    • 不同事务RR和RC下加锁的规则
  • MVCC
    • mvcc进一步提高并发
    • 快照读和当前读
并发所带来的的问题脏写B事务修改且已经提交的数据被另外一个事务回滚(分析图如下)
如何解决脏读呢?
这里简单说一下 , 就是事务A开启后就给这个记录上锁,事务B要操作相同的记录只能等待拿到锁
因为数据库的操作是在内存中执行的 , 在 Buffer Pool 中执行所以就算是这种串行也不会特别慢
InnoDB关于事务、锁、MVCC专题

文章插图
脏读B事务读取到了A事务尚未提交的数据(分析图如下)
InnoDB关于事务、锁、MVCC专题

文章插图
不可重复读A事务读到了B事务已经提交的数据,即A事务在B事务提交之前和提交之后读取到的数据内容不一致(AB事务操作的是同一条数据)(分析图如下)
InnoDB关于事务、锁、MVCC专题

文章插图
幻读B事务读到了A事务已经提交的数据,即A事务执行新增或删除操作,B事务在A事务前后读到的数据数量不一致
幻读和不可重复读有点类似(这里就不画图了)不可重复读强调的是数据的值不一样 , 重点是修改,而幻读强调的是记录的数量不一样,重点是新增或删除 。就好像是看花眼产生重影一样 。
事务事务的特性:ACIDA:原子性(Atomicity),原子性是指事务是一个不可分割的工作单位,事务中的操作,要么都发生,要么都不发生 。
例:假设你在购物车里添加了两件衣服:上衣和裤子,当你把两件衣服作为一个订单提交支付的时候,要么两件衣服一起支付成功,要么都失败,不可能存在上衣付完钱了,裤子还没付完的情况,反之亦然 。
C:一致性(Consistency),在一个事务中,事务前后数据的完整性必须保持一致 。
例:假设用户A和用户B两者的钱加起来一共是200,那么不管A和B之间如何转账,转几次账,事务结束后两个用户的钱相加起来应该还得是200,这就是事务的一致性 。
I:隔离性(Isolation) , 存在于多个事务中,事务的隔离性是指多个用户并发访问数据库时,一个用户的事务不能被其它用户的事务所干扰 , 多个并发事务之间数据要相互隔离 。
例:对于任意两个并发的事务T1和T2,在事务T1看来,T2要么在T1开始之前就已经结束,要么在T1结束之后才开始,这样每个事务都感觉不到有其他事务在并发地执行 。
D:持久性(Durability),持久性是指一个事务一旦被提交,它对数据库中数据的改变就是永久性的,接下来即使数据库发生故障也不应该对其有任何影响 。
例:我们在操作数据库时,事务提交或者回滚都会直接改变数据库中的值 。
事务的四种隔离级别
  • read uncommitted(读未提交): 一个事务还没提交时,它做的变更就能被别的事务看到,读取尚未提交的数据,不能解决脏读、不可重复读、幻读;
  • read committed(读已提交):一个事务提交之后,它做的变更才会被其他事务看到,读取已经提交的数据,可以解决脏读 ---- oracle默认的,不能解决不可重复读、幻读;
  • repeatable read(可重复读):一个事务执行过程中看到的数据,总是跟这个事务在启动时看到的数据是一致的,可以解决脏读和不可重复读 ---mysql默认的 , 会存在幻读;
  • serializable(串行化):顾名思义是对于同一行记录,“写”会加“写锁”,“读”会加“读锁” 。当出现读写锁冲突的时候,后访问的事务必须等前一个事务执行完成,才能继续执行 。可以解决脏读、不可重复读和虚读---相当于锁表 。
备注:虽然serializable级别可以解决所有的数据库并发问题,但是它会在读取的每一行数据上都加锁,这就可能导致大量的超时和锁竞争问题,从而导致效率下降 。所以我们在实际应用中也很少使用serializable,只有在非常需要确保数据的一致性而且可以接受没有并发的情况下 , 才考虑采用该级别 。
锁为什么要加锁如果有多个并发请求存取数据,在数据就可能会产生多个事务同时操作同一行数据 。

推荐阅读