Spring - TransactionalEventListener 解决事务未提交读取不到数据问题(一)

简介: Spring - TransactionalEventListener 解决事务未提交读取不到数据问题(一)

一、背景

业务处理过程,发现了以下问题,代码一是原代码能正常执行,代码二是经过迭代一次非正常执行代码

代码一:以下代码开启线程后,代码正常执行

ThreadPoolExecutor executor = new ThreadPoolExecutor(5, 10, 200, TimeUnit.MILLISECONDS,
                new ArrayBlockingQueue<Runnable>(5));
@Transactional
public Long test() {
  // ......
  // 插入记录
  Long studentId = studentService.insert(student);
  // 异步线程
  writeStatisticsData(studentId);
  return studentId;
}
private void writeStatisticsData(Long studentId) {
  executor.execute(() -> {
    Student student = studentService.findById(studentId);
    //........
  });
}

代码二:以下代码开启线程后,代码不正常执行

@Transactional
public Long test() {
  // ......
  // 插入记录
  Long studentId = studentService.insert(student);
   // 异步线程
  writeStatisticsData(studentId);
  // 插入学生地址记录
  Long addressId = addressService.insert(address);
  return studentId;
}
private void writeStatisticsData(Long studentId) {
  executor.execute(() -> {
    Student student = studentService.findById(studentId);
    //........
  });
}

二、问题分析

这里使用了spring事务,显然需要考虑事务的隔离级别

2.1、mysql隔离级别

查看mysql隔离级别

SELECT @@tx_isolation;
READ-COMMITTED

读提交,即在事务A插入数据过程中,事务B在A提交之前读取A插入的数据读取不到,而B在A提交之后再去读就会读取到A插入的数据,也即Read Committed不能保证在一个事务中每次读都能读到相同的数据,因为在每次读数据之后其他并发事务可能会对刚才读到的数据进行修改。


2.2、问题原因分析


代码一正常运行的原因


由于mysql事务的隔离级别是读提交,test方法在开启异步线程后,异步线程也开启了事务,同时以读者身份去读 test 方法中插入的 student 记录,但此时 test 方法已经提交了事务,所以可以读取到 student 记录(即在异步方法中可以读取到 student 记录),但此代码有风险,若事务提交的时间晚一点,异步线程也有可能读取不到 student 记录。


代码二不能正常运行的原因


经过上面分析,很明显异步方法中不能读取到 student 记录,由于代码二在异步线程下面又执行了其他操作,延时了test方法中事务的提交,所以代码二不能正常运行。


目录
相关文章
|
18天前
|
Java 数据库 开发者
|
3天前
|
SQL Java 关系型数据库
Spring 事务
Spring 事务
6 1
|
5天前
|
Java 数据库连接 数据库
Spring事务简介,事务角色,事务属性
Spring事务简介,事务角色,事务属性
15 2
|
9天前
|
Java 数据库连接 数据库
16:事务-Java Spring
16:事务-Java Spring
25 5
|
9天前
|
JSON JavaScript Java
从前端Vue到后端Spring Boot:接收JSON数据的正确姿势
从前端Vue到后端Spring Boot:接收JSON数据的正确姿势
21 0
|
11天前
|
SQL Java 数据库连接
Springboot框架整合Spring JDBC操作数据
JDBC是Java数据库连接API,用于执行SQL并访问多种关系数据库。它包括一系列Java类和接口,用于建立数据库连接、创建数据库操作对象、定义SQL语句、执行操作并处理结果集。直接使用JDBC涉及七个步骤,包括加载驱动、建立连接、创建对象、定义SQL、执行操作、处理结果和关闭资源。Spring Boot的`spring-boot-starter-jdbc`简化了这些步骤,提供了一个在Spring生态中更便捷使用JDBC的封装。集成Spring JDBC需要添加相关依赖,配置数据库连接信息,并通过JdbcTemplate进行数据库操作,如插入、更新、删除和查询。
|
11天前
|
SQL Java 数据库连接
Springboot框架整合Spring Data JPA操作数据
Spring Data JPA是Spring基于ORM和JPA规范封装的框架,简化了数据库操作,提供增删改查等接口,并可通过方法名自动生成查询。集成到Spring Boot需添加相关依赖并配置数据库连接和JPA设置。基础用法包括定义实体类和Repository接口,通过Repository接口可直接进行数据操作。此外,JPA支持关键字查询,如通过`findByAuthor`自动转换为SQL的`WHERE author=?`查询。
|
11天前
|
消息中间件 Java 关系型数据库
Spring事务与分布式事务
这篇文档介绍了事务的概念和数据库事务的ACID特性:原子性、一致性、隔离性和持久性。在并发环境下,事务可能出现更新丢失、脏读和不可重复读等问题,这些问题通过设置事务隔离级别(如读未提交、读已提交、可重复读和序列化)来解决。Spring事务传播行为有七种模式,影响嵌套事务的执行方式。`@Transactional`注解用于管理事务,其属性包括传播行为、隔离级别、超时和只读等。最后提到了分布式事务,分为跨库和跨服务两种情况,跨服务的分布式事务通常通过最终一致性策略,如消息队列实现。
|
12天前
|
监控 Java 测试技术
Spring Boot与事务钩子函数:概念与实战
【4月更文挑战第29天】在复杂的业务逻辑中,事务管理是确保数据一致性和完整性的关键。Spring Boot提供了强大的事务管理机制,其中事务钩子函数(Transaction Hooks)允许开发者在事务的不同阶段插入自定义逻辑。本篇博客将详细探讨事务钩子函数的概念及其在Spring Boot中的应用。
34 1
|
15天前
|
XML Java 数据库连接
精妙绝伦:玩转Spring事务编程的艺术
【4月更文挑战第20天】
30 0