MySQL中事务的理解


微信搜索“coder-home”或扫一扫下面的二维码,关注公众号,第一时间了解更多干货分享,还有各类视频教程资源。扫描它,带走我
在这里插入图片描述


事务的并发会带来很多问题。比如脏读、不可重复读、幻读等问题。这么问题怎么修复呢?我们逐个复现一下,然后看下MySQL是怎么修复这些问题的。请参考文章:MySQL事务并发问题和解决方案

事务的概念

数据库事务( transaction)是访问并可能操作各种数据项的一个数据库操作序列,这些操作要么全部执行,要么全部不执行,是一个不可分割的工作单位。事务由事务开始与事务结束之间执行的全部数据库操作组成。

事务的四大特性

事务的四大特性:ACID(Atomicity、Consistency、Isolation、Durability,即原子性、一致性、隔离性、持久性)。下面逐一说明特性的含义。

原子性

一个事务中对数据库所有的操作,要么都成功要么都失败,不能成功一部分失败一部分。

因为原子是参加化学反应的最小单位,所以在数据库事务的特性这里就引用了原子的这样的概念。事务也是对数据库操作的最小单位,这就是事务原子性的特征。

举例说明一下。我们使用经典的例子,两个人之间相互转账来说明事务的原子性的特征。

A向B转账50块钱,会发生两个动作:

  • A的账户减少50块钱
  • B的账户增加50块钱

上面的这两个动作需要同时成功才可以,不能A减少了B没有增加、或者A没有减少B却增加了。发生这两种情况的任何一种都不可以,这两个动作要么都成功,要么都失败。这就是事务的原子性的体现。

一致性

一个 事务执行的结果必须是使数据库从一个一致性状态变到另一个一致性状态。一致性与原子性是密切相关的。

我是不太明白这句话的含义,结合实例我才能理解的比较透彻。我还是举例说明一下吧,还是用转账的经典案例。

  • A和B两人原先各有100块钱
  • A和B两个账户的总数是200块=100+100。
  • 如果此时,A给B转了50块钱,那么A的账户里减少50块,B账户里增加50块这两个动作要么都成功,要么都失败,这是事务的原子性的一种体现。
  • 转账后,A和B两个账户的总数还是200块=50+150。

他们从原先的200=100+100变成另外一个状态的200=50+150,这个一致性状态的变化就是事务的一致性的体现。不能转账前总额是200=100+100,转账后变成250=50+200或者其他结果,这样数据库在事务的前后状态就不一致了,就违背了事务的一致性特征。

隔离性

数据库中多个事务之间是相互独立的,互不干扰的。不能因为某一个事务而影响到其他的事务。

举例说明,还是拿转账的案例来说。

  • A和B之间相互转账,
  • 如果与此同时C和D也在相互转账。
  • E和F之间此时也在相互转账。
  • 那么这三个事务是互不影响的,各自转各自的,他们彼此之间是互相透明的。感知不到其他事务的存在。

这个例子这就是事务隔离性的体现。

说到数据库的隔离性,就不得不提隔离性下面的四个隔离级别。隔离级别分为:读未提交、读已提交、可重复读、串行化四个级别。这4种隔离级别,并行性能依次降低,安全性依次提高。隔离级别越高,数据库的并发性和性能就越低。

当数据库上有多个事务同时执行的时候,就可能出现脏读(dirty read)、不可重复读(non-repeatable read)、幻读(phantom read)的问题,为了解决这些问题,就有了“隔离级别”的概念。

读未提交

读未提交是指,一个事务还没提交时,它做的变更就能被别的事务看到。

换句话理解一下就是:别人改数据的事务尚未提交,我在我的事务中也能读到。

读已提交

读提交是指,一个事务提交之后,它做的变更才会被其他事务看到。

换句话理解一下就是:别人改数据的事务已经提交,我在我的事务中才能读到。

可重复读

可重复读是指,一个事务执行过程中看到的数据,总是跟这个事务在启动时看到的数据是一致的。当然在可重复读隔离级别下,未提交变更对其他事务也是不可见的。

换句话理解一下就是:别人改数据的事务已经提交,我在我的事务中也不去读。

串行化

串行化,又叫序列化,顾名思义是对于同一行记录,“写”会加“写锁”,“读”会加“读锁”。

  • “读”锁和“读”锁之间相互冲突
  • “写”锁和“写”锁之间相互冲突
  • “读”锁和“写”锁之间也相互冲突。

当出现读写锁冲突的时候,后访问的事务必须等前一个事务执行完成,才能继续执行。

换句话理解一下就是:我的事务尚未提交,别人就别想读数据。

持久性

一个事务对数据库的影响是永久的,不会因为时间的改变而改变。即便是数据库发生了重启,事务对数据库的修改也不会因为重启而丢失,事务对数据库的修改是持久性的,也就是说事务对数据库的修改要落地到磁盘上。

我们还是使用转账的例子来说一下。

A给B转了50块钱,不能到了明天或后天这个转账记录就丢失了或失效了,也不能因为数据库重启而导致A向B转账50块钱这个数据记录而丢失。这就是事务的持久性的体现,事务对数据库的修改是永久的写在磁盘上的。

事务并发带来的问题

事务四大特性之一:隔离性的存在表明各个事务之间是互不影响,彼此感知不到对方的存在。

但是在数据库系统中,多事务并发存在是可能导致脏读、不可重复的、幻读的问题出现的。

脏读

脏读是指一个事务在执行过程中,前后读取到的数据不一致,是因为它读取到其它事务update后但未提交的数据

注意:这里的重点是读取到其他事务insert 、update、delete更新后还未提交的数据。

脏读示例图如下所示:
在这里插入图片描述

不可重复读

不可重复读是指一个事务在执行过中,前后读取到的数据不一致,是因为读取到其它事务updatedelete后并且已提交的数据。

注意:这里强调的是读取到其它事务update更新或delete删除后并且已提交的数据。

不可重复读示例如下所示:
在这里插入图片描述

幻读

幻读是指一个事务在执行的过程中,前后读取到的数据不一致,是因为读取到其他事务insert且已提交的数据。

注意:这里强调的是读取到其他事务insert插入后并且已提交的数据。读到更新和删除的的数据不算是幻读,算做不可重复读。

幻读示例如下所示:
在这里插入图片描述

查看修改MySQL的隔离级别

MySQL中事务的默认隔离级别为可重复读。而像Oracle、SQLserver、postgresql等厂商的数据库的默认事务隔离级别为读已提交。

所以,在从其他数据库产品向MySQL数据库迁移的时候,需要格外注意这一点。如果有必要,则需要将MySQL的默认隔离级别修改为读提交,从而避免业务系统在事务层级可能出现的bug。

  • 查看MySQL的版本

    本实验中所有的操作都是基于MySQL5.7.31版本来做的。不同的MySQL版本,有些参数名称可能不同,这里需要稍微注意一下。MySQL的版本如下:

    mysql> select version();
    +------------+
    | version()  |
    +------------+
    | 5.7.31-log |
    +------------+
    1 row in set (0.01 sec)
    
  • 查看MySQL当前默认的事务隔离级别

    在修改之MySQL事务隔离级别之前,我们先查看一下当前使用的事务隔离级别是什么,如何查看?可以使用show variables like 'transaction_isolation';命令来查看。如下所示:

    mysql> show variables like 'transaction_isolation';
    +-----------------------+-----------------+
    | Variable_name         | Value           |
    +-----------------------+-----------------+
    | transaction_isolation | REPEATABLE-READ |
    +-----------------------+-----------------+
    1 row in set (0.01 sec)
    
    mysql>
    
  • 修改MySQL的默认隔离级别

    修改的时候,我们可以基于session级别来修改也可以基于global级别来修改。实验的时候,建议使用session级别来修改就可以。修改MySQL的session级别的隔离级别命令如下:

    mysql> set session transaction_isolation='READ-UNCOMMITTED';
    Query OK, 0 rows affected (0.00 sec)
    
    mysql> show variables like 'transaction_isolation';
    +-----------------------+------------------+
    | Variable_name         | Value            |
    +-----------------------+------------------+
    | transaction_isolation | READ-UNCOMMITTED |
    +-----------------------+------------------+
    1 row in set (0.01 sec)
    
    mysql>
    

接下来我会针对每一种隔离级别下面如何解决脏读、不可重复读、幻读来做针对性的实验操作。
请参考文章:MySQL事务并发问题和解决方案


微信搜索“coder-home”或扫一扫下面的二维码,关注公众号,第一时间了解更多干货分享,还有各类视频教程资源。扫描它,带走我
在这里插入图片描述


  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值