当前位置: 首页 > news >正文

事务隔离级别实战

事务隔离级别

在数据库系统中,事务隔离级别用于定义事务之间的隔离程度,主要是为了解决并发事务访问数据时可能出现的问题,如脏读、不可重复读和幻读。常见的事务隔离级别有以下四种,不同的数据库对这些隔离级别的支持和实现细节可能会有所不同。

读未提交(Read Uncommitted)

  • 特点:这是最低的隔离级别,允许一个事务读取另一个事务尚未提交的数据。
  • 问题:会导致脏读问题,即一个事务读取到了另一个事务未提交的数据,如果该事务回滚,那么读取到的数据就是无效的。
  • 示例:假设事务 A 更新了某条记录,但还未提交,此时事务 B 读取了这条被更新的数据。如果事务 A 后来回滚了,那么事务 B 读取到的数据就是无效的。
  • 适用场景:很少使用,因为脏读会带来很多问题,但在对数据一致性要求不高的场景下,如某些统计分析系统,可能会使用这种隔离级别来提高性能。

读已提交(Read Committed)

  • 特点:一个事务只能读取另一个事务已经提交的数据。
  • 问题:解决了脏读问题,但可能会出现不可重复读问题。即一个事务在多次读取同一数据时,由于其他事务对该数据进行了更新并提交,导致每次读取的结果不一致。
  • 示例:事务 A 在第一次读取某条记录时,得到了一个值。然后事务 B 更新了这条记录并提交。当事务 A 再次读取这条记录时,得到了不同的值。
  • 适用场景:大多数数据库系统默认的隔离级别,适用于大多数对数据一致性有一定要求的场景,如银行系统的转账操作。

可重复读(Repeatable Read)

  • 特点:保证在一个事务中多次读取同一数据时,其结果是一致的。在事务执行期间,其他事务不能对该事务正在读取的数据进行更新操作。
  • 问题:解决了不可重复读问题,但可能会出现幻读问题。幻读是指一个事务在执行查询操作时,由于其他事务插入或删除了符合查询条件的记录,导致该事务在后续的查询中发现结果集发生了变化。
  • 示例:事务 A 在第一次查询时,得到了符合某个条件的一组记录。然后事务 B 插入了一条符合该条件的记录并提交。当事务 A 再次执行相同的查询时,发现结果集中多了一条记录。
  • 适用场景:适用于对数据一致性要求较高的场景,如财务系统的报表生成。MySQL 的 InnoDB 存储引擎默认使用可重复读隔离级别。

串行化(Serializable)

  • 特点:这是最高的隔离级别,它强制事务串行执行,即一个事务执行完后,另一个事务才能开始执行。
  • 问题:避免了脏读、不可重复读和幻读问题,但会导致并发性能大幅下降,因为事务之间不能并发执行,只能依次执行。
  • 示例:如果有多个事务需要访问同一数据,它们会按照顺序依次执行,不会出现并发冲突。
  • 适用场景:适用于对数据一致性要求极高,且对并发性能要求不高的场景,如某些金融交易系统。

查看mysql8默认事务隔离级别

mysql默认事务隔离级别是可重复读

SHOW VARIABLES LIKE 'transaction_isolation';

 

场景实战

避免一级缓存的干扰,由于mybatis存在一级缓存,所以使用以下方式的时候每次方法调用返回的对象是同一个

userService.getBaseMapper().selectById(50)private User getById(Object id) {LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();wrapper.eq(User::getId, id);return userService.getOne(wrapper);
}
<select id="getByUserId" resultType="cn.hollycloud.server.entity.User" parameterType="long">select * from user where id = #{id}
</select>

 我们可以通过给xml加flushCache="true"的方式避免一级缓存

<select id="getByUserId" resultType="cn.hollycloud.server.entity.User" parameterType="long" flushCache="true">select * from user where id = #{id}
</select>

测试1,开启断点到testTransaction方法第一行,这时事务已经开始,我们再把数据库user id是1的积分从10改成20,再去读用户,这时读到的积分是多少?是20

测试2,先读一次user,打上断点,这时改下用户积分,从10改到20,再读一次用户,这时数据库的用户积分是20,但是我获取到的用户积分还是10,这就是可重复读,前后两次读到的数据是一致的

 测试3,设置事务的隔离级别为Isolation.READ_COMMITTED,重复以上试验,会发现第一次返回10,第二次返回20

相关文章:

  • 跨平台嵌入式音视频开发指南:EasyRTC音视频通话的多场景适配与AI扩展能力
  • 一路磕磕绊绊解决flutter doctor 报错CocoaPods not installed
  • 【软件系统架构】事件驱动架构
  • 【音视频】MP4解封装
  • [特殊字符] 基于大模型的地理领域文档中英互译自动化方案
  • React 组件类型详解:类组件 vs. 函数组件
  • 【并行分布计算】Hadoop完全分布搭建
  • 【机器学习】大数据时代,模型训练慢如牛?解锁Spark MLlib与分布式策略
  • 【ROS】局部规划器概述
  • 抽象的https原理简介
  • React JSX 语法深度解析与最佳实践
  • 第九节:React HooksReact 18+新特性-React 19的use钩子如何简化异步操作?
  • React 开放封闭原则详解,构建可扩展的应用
  • React Native 0.79 稳定版发布,更快的工具、更多改进
  • 6、事件处理法典:魔杖交互艺术——React 19 交互实现
  • MySQL数据库安装配置详细教程
  • AUTOSAR图解==>AUTOSAR_SWS_DefaultErrorTracer
  • 网络层IP协议知识大梳理
  • 探寻Gson解析遇到不存在键值时引发的Kotlin的空指针异常的原因
  • docker Windows 存放位置
  • 网站建设问卷调查/制作网页设计公司
  • 深圳有做网站公司/福州百度seo代理
  • 构建网站的步骤/如何让关键词排名靠前
  • ajax登陆wordpress/百度产品优化排名软件
  • 网站开发好了如何上线/惠州seo网站推广
  • steam官方网站下载/南宁网络推广服务商