时人不识凌云木,直待凌云始道高。这篇文章主要讲述#yyds干货盘点#MySQL学习-为啥有时候事务的隔离没有生效相关的知识,希望能为你提供帮助。
前言我们知道mysql的事务可以实现语句之间的隔离(ACID中的I),使得各个操作之间互不干扰;
但是有时候我们会发现事务并没有起到隔离的作用;
下面我们就来解释下事务隔离失效的原因以及相关的玩具场景;
目录
- 事务的启动时机
- 事务隔离失效的例子
- 解决办法
我们前文了解了事务的启动方式分为显式启动(begin)和隐式启动;
而我们一般采用的启动方式就是显式启动,即通过begin来启动事务;
但是这里的
begin
并不会马上启动事务,它只是表示事务的创建时机,真正启动事务是在后续的第一条SQL语句执行时;这就是为啥有时候明明开启了事务,但是没有起到隔离作用的原因;
当然如果是隐式启动事务,那么就不会存在这个问题;
【#yyds干货盘点#MySQL学习-为啥有时候事务的隔离没有生效】因为隐式启动就是一条SQL语句执行时自动开启一个事务,然后语句执行完成后自动提交事务,这样在语句执行期间 就不会存在间隙,其他语句也就无法影响到这个语句的执行;
但是隐式启动只能实现隔离性,无法保证操作期间数据的一致性,所以一般不推荐隐式启动;
2. 事务隔离失效的例子
例子的思路就是:
- 开启两个事务
- 然后在第一个事务begin之后,执行第一条SQL语句之前,启动第二个事务,并修改一条数据;
- 再回到事务A去查询这条数据
- 如果查询到的是修改后的数据,则说明事务A没有起到隔离的作用;
begin;
文章图片
这时事务A并没有启动,begin只是用来创建事务;
接下来我们在窗口2中开启事务B(begin),修改一条数据(之前的name=1,现在改为jalon),提交事务;
文章图片
这时我们再回到窗口1,去事务A中查询id=1这条数据,会发现查到的是最新的
name=jalon
;文章图片
这是因为事务A的begin开启事务后并没有马上启动事务,而是在下面的
select * from test where id=1;
语句执行时,才真正启动事务;这时会创建一个视图,用来确保事务A执行期间数据的一致性;
而这个时候,事务B已经修改了id=1的数据,并提交了事务;
所以此时创建的视图会包含最新的数据,即事务B修改过的数据;
3. 解决办法
其实事务的启动有一个快捷方法:
start transaction with consistent snapshot
;这个命令的意思就是:创建+启动事务,相当于begin命令以及begin到第一条SQL语句执行之间的间隙;
这时我们再重复上面的例子,不过不是以begin的形式开启事务,而是快捷命令
start transaction with consistent snapshot
:下面的窗口1先创建并启动事务A,然后窗口2创建事务B,修改数据,提交事务B;
文章图片
然后再回到窗口1查询数据;
文章图片
可以看到,查询的数据还是旧的数据(新数据为
name=ling
);这说明事务A的隔离生效了,这就是
start transaction with consistent snapshot
的功劳;总结
- 事务隔离失效的原因:
- 因为事务的begin只是创建事务,而真正启动事务是在第一条SQL语句执行时;
- 如果在begin和执行第一条SQL语句期间,其他事务修改了数据,那么事务A就会读到最新的数据,而不是begin时的数据;
- 事务隔离失效的解决:
- 使用创建并启动事务的快捷命令,
start transaction with consistent snapshot
; - 如果隔离级别是读提交RC,那么该命令就无效了,因为只要一个事务提交了更新,其他事务都会读到最新的数据,而不是事务启动时的数据
- 使用创建并启动事务的快捷命令,
- 事务视图的创建时机:
- 如果是begin命令,则是在第一条SQL语句执行时创建一致性视图
- 如果快捷启动命令
start transaction with consistent snapshot
,则该命令执行时就会创建一致性视图
推荐阅读
- 详解Tensorboard及使用教程
- Android技术分享| Android 自定义View多人视频通话控件
- vivo全球商城全球化演进之路——多语言解决方案
- HarmonyOS-基于canvas绘制复古钟表
- #yyds干货盘点# 基于STM32+ESP8266+华为云设计的智能家居控制系统
- #yyds干货盘点# 超全面Git知识总结!
- XtraBackup实现MySQL数据库全量+增量+Binlog恢复库
- MyCAT实现MySQL数据库读写分离
- 在linux中如果查看进程,不懂得点进来吧!另外附加了如何静态启动进程!