mysql事务隔离级别

首先, 标准定义的事务隔离级别分为以下

事务隔离级别
事务隔离级别脏读不可重复读幻读
读未提交(Read Uncommitted)
读已提交(Read Committed)
可重复读(Repeatable Read)
串行化(Serializable)

 

 

 

 

 

 

脏读: 读取到其他事务还未提交的数据

比如事务A修改了某行数据, 此时事务A还未提交, 事务B却能读取到被事务A修改后还未提交的该行数据, 产生了脏读. 此时如果事务A进行回滚撤销, 那么事务B读取到的该行数据便是脏数据.

测试验证:

1. 原始数据为

2. 设置mysql为读未提交(read uncommitted)级别

3. 开启事务A, 对id=1的该行数据进行修改, 但事务A不提交

4. 开启事务B, 查询id=1的数据行

以上测试可知, 事务B读取到了事务A还未提交的修改数据, 由此可知, "读未提交" 隔离级别下, 产生了脏读!

 

不可重复读: 对于数据库中的某个数据, 一个事务内多次查询却返回了不同的数据值, 重复读取时数据不一致.

比如事务A中对同一条数据重复读取, 第一次读取和第二次读取的间隙中, 事务B更改了该条数据, 那么在事务A中第二次读取的结果和第一次不一致, 产生了不可重复读问题.

测试验证:

1. 原始数据为

2. 设置mysql为读已提交(read committed)级别 (这里设置成读未提交当然也行)

3. 开启事务A,  事务A中进行两次重复查询, 第一次与第二次之间间隔15s, 在15s间隔间, 开启事务B, 对该行id=1的数据进行修改并提交.

以上测试可以看到, 同一个事务中多次进行相同查询, 在这个多次读间隙中其他事务一旦做了修改, 重复读取的数据将不一致, 产生了不可重复读!  "读未提交" 和 "读已提交" 隔离级别都将产生该问题.

 

幻读: 是指当事务不是独立执行时发生的一种现象, 幻读针对的是新增场景

比如事务A针对fname=a的数据进行全体更新, 此时事务B添加了一条新数据, 而该新数据fname=a, 事务A更新完之后, 发现事务B提交的该行数据没有被更新到, 似乎产生了幻觉一样, 这就是幻读

测试验证:

1. mysql innoDB设置可重复读, 基础数据如下

2. 开启事务A,  事务A中先更新fname=a行的create_time, 然后间隔15s, 再查询fname=a的行, 事务A执行的同时, 开启事务B, 执行insert, 该insert行的fname=a, 为了防止事务A中的 select 快照读, 我们对 select 增加 for update

// 由以下事务A与事务B的结果可看出, 在mysql InnoDB引擎的可重复读隔离级别下, 事务A中更新了fname=a的行, 在事务A没进行提交前, 事务B的插入fname=a的操作, 一直处于等待状态, 直到事务A执行成功后, 事务B才插入成功, 这样就避免了幻读的产生

// 以下可看出, 事务B中对fname=a的insert操作, 此时处于阻塞状态, 因为事务A还没提交fname=a的更新操作, 没释放间隙锁

// 以下可看出, 由于事务A提交后, 此时事务B的insert操作才成功执行

 

这时我们就会有一个疑问, 不是说数据库隔离级别为可重复读时, 无法避免幻读吗?

这是因为mysql InnoDB引入了间隙锁, 它会在你修改或删除指定的行的间隙之间加锁, 那么你在执行修改或者删除特定条件的数据时, 由于间隙锁的存在, 其他事务无法插入该相同条件的行, 只能等待你执行完成后, 释放间隙锁.

所以, 在这种场景下, mysql innoDB引擎, 指定可重复读隔离级别, 可以避免幻读的产生!

(ps: 间隙锁详情请参考    https://www.cnblogs.com/gaosf/p/11142177.html                      http://hedengcheng.com/?p=771)

 

结论: 在mysql innoDB 可重复读隔离级别下, 可以避免部分幻读的产生(注意是部分情况!), innoDB会在更新/删除行的间隙之间添加间隙锁, 此时其他事务insert该范围内的数据时, 由于有间隙锁的存在, 无法插入数据.

 

那么, 如果在innoDB提交读隔离级别下, 又是什么样的情况呢?

测试验证:

1. 设置隔离级别为提交读, 基础数据如下

2. 开启事务A,  事务A中先更新fname=a行的create_time, 然后间隔15s, 再查询fname=a的行, 事务A执行的同时, 开启事务B, 执行insert, 该insert行的fname=a

// 以下我们可以看到, 事务A执行还未提交的过程中, 事务B针对fname=a的行插入并没有阻塞, 而是直接插入成功, 而事务A中15s后的查询, 查到了事务B提交的记录(提交读读到了其他事务新增的数据), 事务A中的更新create_time也未对事务B中新插入行的create_time修改成功, 此时产生了幻读. (我明明对fname=a的行更新了create_time = 1990-01-01 00:00:00, 查询时却发现有一条没更新成功, 像产生了幻觉)

结论: 在innoDB提交读隔离级别下, 产生了幻读, 事务A修改fname = a数据时, 再次查询时发现有的没更新成功, 原因是在更新后再查询时, 别的事务新增了fname = a的数据.

 

mysql隔离级别

  • 读未提交: 读取到其他事务还未提交的数据
  • 读已提交: 只能读取到其他事务已经提交的数据, 该隔离级别下, 如果一个事务中重复相同条件的读取, 这个过程中一旦其他事务对该数据进行更改, 可能导致重复读取的数据不一致
  • 可重复读: 事务中重复读取指定条件数据时, 即使其他事务对该数据进行更新, 依然能保证重复读取到的数据一致, 但是并不意味着数据没有被更改, 其实本质上数据已经被更改了, 读取的是快照(详细可以查看MVCC机制)
  • 串行化: 事务一个一个串行执行
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值