【精品】数据库事务( 以MySQL8.x为例 )

相关博客:事务相关概念

本章示例表及数据如下:

  • 数据库:
    在这里插入图片描述
  • 默认数据
    在这里插入图片描述

示例

  • start transaction:开启事务
  • rollback:回滚事务
  • commit:提交事务

示例1:演示事务提交

在这里插入图片描述

示例2:演示事务回滚

在这里插入图片描述

事务隔离级别

事务隔离级别名称脏读不可重复读幻读
read-uncommitted读未提交,也叫脏读
read-committed不可重复读,也叫读已提交
repeatable-read可重复读,默认级别
serializable串行化

说明:

  • 隔离级别为读已提交时,写数据只会锁住相应的行。
  • 读已提交解决了脏读,但是两次读取的结果可能会不一致。
  • 隔离级别可重复读解决了多次查询结果都是一样的问题,但是如果事务执行期间有其他事务插入新数据,此时会产生幻读。
  • 隔离级别为可重复读时,如果检索条件有索引(包括主键索引)的时候,默认加锁方式是next-key 锁;如果检索条件没有 索引,更新数据时会锁住整张表。一个间隙被事务加了锁,其他事务是不能在这个间隙插入记录的,这样可以防止幻读。
  • 事务隔离级别为串行化时,读写数据都会锁住整张表
  • 隔离级别越高,越能保证数据的完整性和一致性,但是对并发性能的影响也越大。

查看MySQL默认的事务隔离级别

示例3:
在这里插入图片描述

注意:在MySQL8之前的命令为:select @@tx_isolation

读未提交(read uncommitted)

  • 两个事务,一个事务未提交的数据,另一个事务可以读取到,这里读取到的数据叫做“脏数据”。
  • 这种隔离级别最低,这种级别一般是在理论上存在,实际应用中数据库隔离级别一般都高于该级别。

示例4:
第一步:打开客户端A,设置当前事务模式为read uncommitted(未提交读),查询tb_balance表zhangsan的money的初始值:
在这里插入图片描述
第二步:在客户端A的事务提交之前,打开另一个客户端B,更新tb_balance表zhangsan的money的值:
在这里插入图片描述
第三步:此时,虽然客户端B的事务还没提交,但是在客户端A已经可以查询到B已经更新的数据:
在这里插入图片描述
第四步:客户端B的事务因为某种原因回滚,它的所有的操作都将会被撤销。
在这里插入图片描述
第五步:客户端A查询到的数据其实就是脏数据了:
在这里插入图片描述
在客户端A执行执行更新语句zhangsan的money没有变成300,居然是400,数据不一致!

读已提交(read committed)

  • Oracle默认隔离级别
  • 两个事务,数据只有一个事务提交了后,另一个事物才能读取到,即:对方事物提交之后的数据,当前事物才能读取到。
  • 读已提交隔离级别高于读未提交。这种级别可以避免“脏数据”,但是会导致“不可重复读取”,存在幻读问题

示例5:
第一步:打开客户端A设置当前的事务隔离级别为read committed (未提交读)查询表tb_balance的所有记录:
在这里插入图片描述
第二步: 将客户端B的事务的隔离级别调整为read committed级别,并开启事务,更新表tb_balance
在这里插入图片描述
第三步:此时,客户端B的事务还没有提交,客户端A是不能查询到B已经更新的数据,解决了脏数据的问题:
在这里插入图片描述
第四步:客户端B提交事务
在这里插入图片描述
第五步:客户端A执行查询,结果就回发现与上一次查询结果不同,就产生了不可重复读的问题
在这里插入图片描述

可重复读(repeatable read)

  • MySQL默认隔离级别
  • 两个事务,一个事务提交之后的数据,另一个事务读取不到
  • 这种隔离级别高于读已提交,可以避免“不可重复读取”,但是会导致“幻像读”

示例6:
第一步:打开客户端A将事务的隔离级别调整为repeatable read 级别

在这里插入图片描述
第二步: 打开客户端B将事务的隔离级别调整为repeatable read级别,并对表tb_balance进行更新,但并未提交事务
在这里插入图片描述
第三步:在客户端A查询表tb_balance的所有记录,没有出现脏读的情况。
在这里插入图片描述
第四步:客户端B修改数据后提交了事务。
在这里插入图片描述
第五步:在客户端A查询表tb_balance的所有记录,没有出现不可重复读的情况。
在这里插入图片描述
第六步:在客户端A执行更新语句发现数据的一致性得到保证。在这里插入图片描述
之所以数据的一致性得到保证,原因是:在可重复读的隔离级别下,MySQL采用的是MVCC机制,select 操作不会更新版本号,是快照读(历史版本);而insert、update和delete会更新版本号,是当前读(当前版本)。
第七步:打开客户端B,尝试更新zhangsan的数据,会失败,这说明可重复隔离读级别下MySQL8已经不出现幻读的情况了。
在这里插入图片描述

串行化(serializable)

Serializable完全串行化的读,每次读都需要获得表级共享锁,读写操作相互互斥,这样可以更好的解决数据一致性的问题,但是同样会大大的降低数据库的实际吞吐性能。所以该隔离级别因为并发性比较低、损耗太大,一般很少在开发中使用。

  • MySQL中事务隔离级别为serializable时会锁表,因此不可能出现脏读数据、不可重复读、幻读的情况。
  • 两个事务,当一个事务操作数据库时,另一个事务只能排队等待
  • 这种级别可以避免“幻像读”,每一次读取的都是数据库中真实存在数据,多个事务之间串行,而不并发。
  • 这种隔离级别很少使用,吞吐量太低,用户体验差

第一步:在客户端A中设置当前事务模式为Serializable,同时开启事务:
在这里插入图片描述
第二步:在客户端B中设置当前事务模式为serializable,插入一条记录,此时表tb_balance已经被锁定。
在这里插入图片描述
因为已经发生了锁表,所以此时在客户端中再次执行查询会报错:
在这里插入图片描述

评论 13
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

梁云亮

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值