logo
当前位置:首 页 > 编程技术 >后端开发 >mysql > 查看文章

MySQL的事务隔离级别

mysql, 后端开发, 编程技术 你是第2155个围观者 0条评论 供稿者: 标签:,

今天忽然被问到M有SQL的事务隔离级别有几个,今天复习下。

  1. READ-UNCOMMITTED
  2. READ-COMMITTED
  3. REPEATABLE-READ
  4. SERIALIZABLE

这个4个级别

 

什么是事务?

 

事务拿我们票务系统来说事:游客在购票 有2个操作,一个是生成一个订单信息、一个是生成票面信息 。生成订单信息后 ,可能系统问题或者票面值的问题(假设之前没有验证票的信息)。没有生产票面信息。这个就不对了,系统需要生成订单和票面信息,要么一起成功,要么同时失败。

 

事务最经典也经常被拿出来说例子就是转账了。假如小明要给小红转账1000元,这个转账会涉及到两个关键操作就是:将小明的余额减少1000元,将小红的余额增加1000元。万一在这两个操作之间突然出现错误比如银行系统崩溃,导致小明余额减少而小红的余额没有增加,这样就不对了。事务就是保证这两个关键操作要么都成功,要么都要失败。

 

了解了事务的大致作用之后呢,来了解下事务的特性。

 

事务的特性(ACID)

  1. 原子性: 事务是最小的执行单位,不允许分割。事务的原子性确保动作要么全部完成,要么完全不起作用;
  2. 一致性: 执行事务前后,数据保持一致,多个事务对同一个数据读取的结果是相同的;
  3. 隔离性: 并发访问数据库时,一个用户的事务不被其他事务所干扰,各并发事务之间数据库是独立的;
  4. 持久性: 一个事务被提交之后。它对数据库中数据的改变是持久的,即使数据库发生故障也不应该对其有任何影响。

并发事务带来的问题

 

在典型的应用程序中,多个事务并发运行,经常会操作相同的数据来完成各自的任务(多个用户对统一数据进行操作)。并发虽然是必须的,但可能会导致以下的问题。

  • 脏读(Dirty read): 当一个事务正在访问数据并且对数据进行了修改,而这种修改还没有提交到数据库中,这时另外一个事务也访问了这个数据,然后使用了这个数据。因为这个数据是还没有提交的数据,那么另外一个事务读到的这个数据是“脏数据”,依据“脏数据”所做的操作可能是不正确的。

举个例子: 小明正在访问数据库给客户修改票面的信息【例如取票码不知为什么出现了重复,需要修改下】他进行了修改,。但是修改还没有提交到数据库中,这个时,小红也访问到这个客户的信息了【客户又打电话来投诉要取票码了】,因为这个时候小明还没有提交修改数据,这个时候的数据是还没有提交修改的数据,那么小红读取出来的就是”脏数据“,小红用这个数据做出的给游客的访问妥妥的会出问题的。

 

  • 丢失修改(Lost to modify): 指在一个事务读取一个数据时,另外一个事务也访问了该数据,那么在第一个事务中修改了这个数据后,第二个事务也修改了这个数据。这样第一个事务内的修改结果就被丢失,因此称为丢失修改。 例如:事务1读取某表中的数据A=20,事务2也读取A=20,事务1修改A=A-1,事务2也修改A=A-1,最终结果A=19,事务1的修改被丢失

 

还是那个例子:小红提供数据给游客,游客发现还是不能用,而且和刚刚他原来的取票码是一样的,然后呢,游客就又投诉了,小红这个时候来了,她修改了状态为游客投诉,备注是取票码错了,游客特别生气,加急 处理。这个时候呢,小明也来了。因为他刚刚操作了订单,忘了修改状态和备注了。小明修改了状态为已经没有问题了,然后备注是修改完成。然后这个订单小红做出的有问题需要反馈的这个状态和备注就被覆盖了。这个就是丢失修改了。

 

  • 不可重复读(Unrepeatableread): 指在一个事务内多次读同一数据。在这个事务还没有结束时,另一个事务也访问该数据。那么,在第一个事务中的两次读数据之间,由于第二个事务的修改导致第一个事务两次读取的数据可能不太一样。这就发生了在一个事务内两次读到的数据是不一样的情况,因此称为不可重复读。

还是票出问题了,这次游客还没去取票,他买好了票,他买好后获取了订单信息。刚好这时小明呢,下午循例打开了数据库来检查下,然后发现了重复的取票码的问题,然后他就修改了2个重复的取票码。游客这时呢,点击了分享发给了他的家人。刚好这个分享时需要读取后端的取票码数据分享的,2次事务读取的取票码不一样这个就是不可重复读了

  • 幻读(Phantom read): 幻读与不可重复读类似。它发生在一个事务(T1)读取了几行数据,接着另一个并发事务(T2)插入了一些数据时。在随后的查询中,第一个事务(T1)就会发现多了一些原本不存在的记录,就好像发生了幻觉一样,所以称为幻读。

这次这个游客生气了,投诉到景点的特别特别大的领导那里。然后领导要求这个运营室处理下这个事情,运营室的室长开会告诉了小红,然后告诉了开发室的室长这个事情,然后让开发室室长送他们一张小朋友的票。开发室的室长也开会了,让小明加急处理加一张小孩子的票。小红点开查看了下订单的信息发现是2个大人的票,然后同时小明保存了数据。小红刚刚不小心关了订单。再次打开,发现怎么是2个大人还多了一个小孩的票呢? 一定是最近加班太多了,出现幻觉了。

 

不可重复度和幻读区别:

不可重复读的重点是修改,幻读的重点在于新增或者删除。

 

小明修改了取票码,搞的游客2个取票码不一样的情况,这个就是不可重复读。数据的问题在修改

 

小明添加了一个儿童票搞的小红感觉自己出现幻觉,是不是自己刚刚看错了。明明刚刚是2人现在便3人了。

这个就是幻读。感觉自己出现幻觉了。

 

事务隔离级别

 

SQL 标准定义了四个隔离级别:

 

  • READ-UNCOMMITTED(读取未提交): 最低的隔离级别,允许读取尚未提交的数据变更,可能会导致脏读、幻读或不可重复读。

 

  • READ-COMMITTED(读取已提交): 允许读取并发事务已经提交的数据,可以阻止脏读,但是幻读或不可重复读仍有可能发生。

 

  • REPEATABLE-READ(可重复读): 对同一字段的多次读取结果都是一致的,除非数据是被本身事务自己所修改,可以阻止脏读和不可重复读,但幻读仍有可能发生。

 

  • SERIALIZABLE(可串行化): 最高的隔离级别,完全服从ACID的隔离级别。所有的事务依次逐个执行,这样事务之间就完全不可能产生干扰,也就是说,该级别可以防止脏读、不可重复读以及幻读。
隔离级别 脏读 不可重复读 幻影读
READ-UNCOMMITTED
READ-COMMITTED ×
REPEATABLE-READ × ×
SERIALIZABLE × × ×

 

MySQL InnoDB 存储引擎的默认支持的隔离级别是 REPEATABLE-READ(可重读)。我们可以通过

  1. SELECT @@tx_isolation;

 

命令来查看,MySQL 8.0 该命令改为

  1. SELECT @@transaction_isolation;

  1. mysql> SELECT @@tx_isolation;
  2. +-----------------+
  3. | @@tx_isolation |
  4. +-----------------+
  5. | REPEATABLE-READ |
  6. +-----------------+

这里需要注意的是:与 SQL 标准不同的地方在于InnoDB 存储引擎在 **REPEATABLE-READ(可重读)事务隔离级别下使用的是Next-Key Lock 锁算法,因此可以避免幻读的产生,这与其他数据库系统(如 SQL Server)是不同的。所以说InnoDB 存储引擎的默认支持的隔离级别是 REPEATABLE-READ(可重读) 已经可以完全保证事务的隔离性要求,即达到了 SQL标准的SERIALIZABLE(可串行化)**隔离级别。

因为隔离级别越低,事务请求的锁越少,所以大部分数据库系统的隔离级别都是READ-COMMITTED(读取提交内容):,但是你要知道的是InnoDB 存储引擎默认使用 **REPEATABLE-READ(可重读)**并不会有任何性能损失。

InnoDB 存储引擎在 分布式事务 的情况下一般会用到**SERIALIZABLE(可串行化)**隔离级别。

 

实际情况演示

在下面我会使用 2 个命令行mysql ,模拟多线程(多事务)对同一份数据的脏读问题。

MySQL 命令行的默认配置中事务都是自动提交的,即执行SQL语句后就会马上执行 COMMIT 操作。如果要显式地开启一个事务需要使用命令:START TARNSACTION

我们可以通过下面的命令来设置隔离级别。

  1. SET [SESSION|GLOBAL] TRANSACTION ISOLATION LEVEL [READ UNCOMMITTED|READ COMMITTED|REPEATABLE READ|SERIALIZABLE]

我们再来看一下我们在下面实际操作中使用到的一些并发控制语句:

  • START TARNSACTION |BEGIN:显式地开启一个事务。
  • COMMIT:提交事务,使得对数据库做的所有修改成为永久性。
  • ROLLBACK:回滚会结束用户的事务,并撤销正在进行的所有未提交的修改。

脏读(读未提交)

 

避免脏读(读已提交)

 

 

不可重复读

 

还是刚才上面的读已提交的图,虽然避免了读未提交,但是却出现了,一个事务还没有结束,就发生了 不可重复读问题。

可重复读

防止幻读(可重复读)

一个事务对数据库进行操作,这种操作的范围是数据库的全部行,然后第二个事务也在对这个数据库操作,这种操作可以是插入一行记录或删除一行记录,那么第一个是事务就会觉得自己出现了幻觉,怎么还有没有处理的记录呢? 或者 怎么多处理了一行记录呢?

幻读和不可重复读有些相似之处 ,但是不可重复读的重点是修改,幻读的重点在于新增或者删除。
 

 

说说梦想,谈谈感悟 ,聊聊技术,有啥要说的来github留言吧 https://github.com/cjx2328

—— 陈 建鑫

陈建鑫
你可能也喜欢Related Posts
footer logo
未经许可请勿自行使用、转载、修改、复制、发行、出售、发表或以其它方式利用本网站之内容。站长联系:cjx2328#126.com(修改#为@)
Copyright ©ziao Studio All Rights Reserved. E-mail:cjx2328#126.com(#号改成@) 沪ICP备14052271号-3