数据库基础系列之【事务与并发一致性问题】

目录

 

事务

概念

特性

举例

总结

并发一致性问题

分类

区分

解决

隔离级别

幻读问题的解决

多版本并发控制(MVCC——Multi-Version Concurrency Control)

InnoDB可重复读级别下MVCC的简化实现操作


事务

  • 概念

事务指的是一组操作的集合,事务的产生,其实是为了当应用程序访问数据库的时候,简化我们的编程模型,不需要我们去考虑各种各样的潜在错误和并发问题

当我们使用事务时,要么提交,要么回滚,我们不会去考虑网络异常了,服务器宕机了,同时更改一个数据怎么去处理它

  • 特性

事务操作的正确性,通过以下几个特性来保障

特性描述
原子性事务不可再分,要么全提交,要么全回滚
隔离性两个事务操作的结果在未提交前互相不可见
持久性

即使发生故障导致数据库崩溃,事务操作的结果应该依然存在

一致性系统从一个正确的状态到另一个正确的状态,即正确的状态前后一致

 

 

 

 

 

 

  • 举例

下面举个例子有助于理解:

在银行,A用户向B用户转账100元

首先,查询A用户余额是否够100元,如果够100元,A账户余额-100元,B账户余额+100元

原子性体现在,查询,A减少,B增加这三个步骤不能分开单独执行,数据库崩溃,则事务不会提交,通过这一组操作才能实现转账

隔离性体现在,转账过程中,有另外一个事务并行处理,两个事务互不干扰,在提交前双方的操作结果对对方都不可见

持久性体现在,如果转账结束,该事务提交完成,即使整个数据库系统崩溃,结果依然不会改变

一致性体现在,转账前后,A减少100元,B就应该增加100元,前后保持正确的一致状态

  • 总结

可见,一个事务操作只有满足一致性,最终的结果才是正确的

在没有并发事务的情况下,事务串行执行,只要满足事务的原子性和持久性,一定满足一致性

在有并发事务的情况下,事务并行执行,除了原子性和持久性之外,还需要满足并发事务的隔离性,才能满足一致性


并发一致性问题

根据上述的情况,在事务并发的情况下,如果不满足隔离性,会产生并发一致性问题,我们对其进行分类

  • 分类

问题描述状态
丢失修改事务AB同一时刻修改数据,A先修改,B后修改,在A未提交前,B的修改将A的修改覆盖AB同时写,B覆盖A,A写入无效
脏读事务A读取到了事务B修改未提交的数据,B将其撤销,A读到的结果与实际结果不符A读B写B撤销,A读的是脏数据
不可重复读事务A多次读取数据,中间事务B、C、D进行写入后直接提交,A多次读结果不一致A多次读未提交,BCD写后直接提交
幻读事务A在前后两次查询同一个范围的时候,后一次查询看到了前一次查询没有看到的数据A对一个范围查询两次,第二次看到了第一次没有查询到的值

 

 

 

 

 

 

  • 区分

要注意 脏读、不可重复读与幻读 的 区别

脏读是读到的数据与实际数据库中存储的数据不同,即读到的是未提交的数据,是错误的结果

不可重复读是多次读到的数据结果不同,但都是数据库中存储的真实值,都是已提交的数据,是正确结果

幻读是一种特殊的不可重复读,不可重复读强调的是修改,而幻读强调的是数据的增删

比如对同一行元素的查询,多次查询到的结果不同,是不可重复读的现象,强调数据被修改

对同一范围多个元素的查询,多次查询看到了不同(多或少)的结果数量,强调数据的增删

深入理解详见:

大白话讲解脏写、脏读、不可重复读和幻读 - 轻风的文章 - 知乎

在数据库中不可重复读和幻读到底应该怎么分? - linganmm的回答 - 知乎

  • 解决

既然是隔离性没有得到保障产生的并发一致性问题,那么就需要通过设置隔离级别来解决

隔离级别

级别描述存在问题
读未提交可以读到其它事务未提交状态的数据存在脏读、不可重复读、幻读问题
读已提交只能读到已提交的事务的数据,读事务完成前,其它事务也可修改解决了脏读问题,但还是有不可重复读、幻读问题
可重复读

只能读到已提交的事务的数据,读事务未完成前,其它事务不能修改

                          (也是Mysql数据库的默认隔离级别)

解决了不可重复读问题,但还是有幻读问题
串行化要求事务序列化执行,只能按序串行执行,不能并发执行解决了幻读问题,但丧失了并发性

 

 

 

 

 

 


以上这几种隔离级别听起来比较容易懂,但是它们又是怎么实现的呢?

在这里我们需要引入锁的机制,在操作系统线程并发的问题中,我们也对其有所了解

而在数据库中锁大致分为以下几种

   类型粒度加锁开销加锁速度冲突概率并发程度
 行级锁最小最大最慢最小最高
 页面锁适中适中适中适中适中
 表级锁最大最小最快最大最低

 

 

 

 

 

上面是按照锁的粒度进行分类,下面按照锁的行为进行分类

                类型                                                                                                   再分类

              读写锁

          (行级锁)

共享锁/读锁/S锁

事务T对数据A加读锁,则T可以读但不可以修改A,其它事务也只能加读锁

排它锁/写锁/X锁

事务T对数据A加写锁,则只允许T读取和修改A

      意向锁

 (表级锁)

意向共享锁/IS锁

事务打算给数据加共享锁前,必须取得该表的意向共享锁(给行加锁需要先获得表锁)

意向排它锁/IX锁

事务打算给数据加排它锁前,必须取得该表的意向排它锁

 

 

 

 

 

 

 

锁机制对于隔离级别的实现如下描述

级别                                                                                              描述
读未提交读数据时不会检查是否有锁,或者使用锁,因此能读到其它事务未提交的状态,产生脏读问题
读已提交

只读取已经提交的数据,读锁在读操作完成后立即释放,因此读完后返回结果,读事务未提交,其它事务可以继续修改,产生不可重复读问题

可重复读

只读取已经提交的数据,读取数据的读锁在事务结束后释放,因此不会产生不可重复读状态,但读写锁是行级锁,产生幻读问题

串行化对整张表加锁,要求事务只能按序串行执行,不能并发执行,解决了幻读问题,但丧失了并发性

 

 

 

 

 


幻读问题的解决

根据上述的介绍,我们可以发现,通过串行化的方式虽然解决了幻读问题,但同时也丧失了并发性,因此幻读的问题并没有真正地得到解决

在可重复读的隔离级别下,Mysql使用的InnoDB引擎通过MVCC + next-key lock的手段解决幻读,那么MVCC和next-key lock又是怎么回事呢?

多版本并发控制(MVCC——Multi-Version Concurrency Control)

要了解什么是MVCC,首先要弄清两个概念:当前读、快照读

 描述
  当前读读取的是当前最新版本,并且需要先获取对应记录的锁
  快照读

 

不加锁的单纯的 select 操作,即不加锁的非阻塞读,如:select * from t_user where number = 1;

将历史数据存一份快照,所以其他事务增加与删除数据,对于当前事务来说是不可见的

 

 

 

 

 

快照读的概念是工作在非串行级别下的,串行级别下的快照读会退化成当前读

InnoDB通过为每个数据行增加两个隐含值的方式来实现MVCC,记录了行的创建时间,以及它的过期时间(删除时间)

每一行都存储了事件发生时的系统版本号,用来替代事件发生时的实际时间,每新开始一个事务,版本号自动递增

  • InnoDB可重复读级别下MVCC的简化实现操作

select

1.只能查找版本号小于等于当前事务的版本号的数据行——可以确保当前事务读取的行,都是在当前事务开始前存在的,或是由当前事务创建或修改的

2.数据行的删除版本号一定是未被定义或者大于当前版本号的——可以确保事务读取的行,在事务读取开始前未被删除

同时满足1.2的数据行才能被返回

总结:新的和未提交事务的版本号较高,我们读不到

delete

为删除每一行保存当前版本号作为删除行标志

insert

为新插入的每一行保存当前版本号作为行版本号

update

插入一行新记录,保存当前系统版本号作为行版本号,同时保存当前版本号到原来行,作为行删除标志

保持两个额外系统版本号,使得大多数读操作都可以不用加锁

总结:更新数据不是在原有基础上覆盖的,而是新插入一行,把原本的保存起来

具体操作详见:MySQL事务隔离之MVCC版本控制

通过以上这种方式,MVCC可以为数据库解决以下问题

  • 在并发读写数据库时,可以做到在读操作时不用阻塞写操作,写操作也不用阻塞读操作,提高了数据库并发读写的性能
  • 同时还可以解决脏读,不可重复读的问题

 

 

 

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值