解决SpringBoot使用@Transactional进行RestTemplate远程调用导致查询数据记录为null的bug

本文主要是介绍解决SpringBoot使用@Transactional进行RestTemplate远程调用导致查询数据记录为null的bug,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

开启事务过程中,如果远程调用查询当前已经开启但没有提交的事务,就会查不到数据。

示例代码

import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;import java.util.Objects;@Slf4j
@RestController
@RequestMapping("simple")
@RequiredArgsConstructor
public class SimpleController {private final SimpleObjectMapper simpleObjectMapper;private final RestTemplate restTemplate;/*** 开启事务过程中,如果远程调用查询当前已经开启但没有提交的事务,就会查不到数据。*/@GetMapping("insert")@Transactional(rollbackFor = Exception.class)//1.开启事务public void insert() {SimpleObject simpleObject = new SimpleObject();simpleObject.setId(2);simpleObject.setName("name" + System.currentTimeMillis());simpleObjectMapper.insert(simpleObject);//2.因为开启了事务,所以这里的 insert 并没有 commit,导致下面远程调用查询数据是空的。SimpleObject simpleObject1 = restTemplate.getForEntity("http://localhost:8080/simple/2", SimpleObject.class, simpleObject.getId()).getBody();log.info("simpleObject1 (这里会输出null):{}",simpleObject1);//3.这里会输出null,因为事务没有提交,数据库不会新增数据if (Objects.isNull(simpleObject1)) {throw new RuntimeException("simpleObject1 is null");}}/*** 被远程调用的查询方法*/@GetMapping("{id}")public SimpleObject selectById(@PathVariable Integer id) {return simpleObjectMapper.selectById(id);}}

抛出异常

2024-05-23 22:49:44.033  INFO 8668 --- [nio-8080-exec-1] MyBatisSqlParsingPlugin     : Execute SQL:
INSERT INTO simple_object  ( id,name )  VALUES  ( 2,'name1716475783993' )
2024-05-23 22:49:44.119  INFO 8668 --- [nio-8080-exec-2] MyBatisSqlParsingPlugin     : Execute SQL:
SELECT id,name FROM simple_object WHERE id=2 
2024-05-23 22:49:44.149  INFO 8668 --- [nio-8080-exec-1] SimpleController        : simpleObject1 (这里会输出null):null
2024-05-23 22:49:44.161 ERROR 8668 --- [nio-8080-exec-1] o.a.c.c.C.[.[.[/].[dispatcherServlet]    : 
java.lang.RuntimeException: simpleObject1 is null

解决办法

1、去掉@Transactional注解(显然不可能,除非不影响正常的业务
2、手动控制事务,但是有些情况下可能不适用,不适用的情况可以使用分布式事务,如:seata等(推荐

手动控制事务

示例代码

import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;import java.util.Objects;@Slf4j
@RestController
@RequestMapping("simple")
@RequiredArgsConstructor
public class SimpleController {private final SimpleObjectMapper simpleObjectMapper;private final RestTemplate restTemplate;private final PlatformTransactionManager platformTransactionManager;//事务管理器private final TransactionDefinition transactionDefinition;// 事务的一些基础信息,如超时时间、隔离级别、传播属性等/*** 使用手动事务,远程调用可以查询到数据。*/@GetMapping("insert2")public void insert2() {//手动事务不能加@Transactional注解,否则优先使用@Transactional注解的事务TransactionStatus transaction = platformTransactionManager.getTransaction(transactionDefinition);//1、手动获取事务SimpleObject simpleObject = new SimpleObject();simpleObject.setId(2);simpleObject.setName("name" + System.currentTimeMillis());simpleObjectMapper.insert(simpleObject);platformTransactionManager.commit(transaction);//2.手动提交事务SimpleObject simpleObject1 = restTemplate.getForEntity("http://localhost:8080/simple/2", SimpleObject.class, simpleObject.getId()).getBody();log.info("simpleObject1 (这里会输出simpleObject1):{}",simpleObject1);//3.这里会输出id = 2的 SimpleObject 对象,因为事务提交,数据库会新增数据if (Objects.isNull(simpleObject1)) {throw new RuntimeException("simpleObject1 is null");}}/*** 被远程调用的查询方法*/@GetMapping("{id}")public SimpleObject selectById(@PathVariable Integer id) {return simpleObjectMapper.selectById(id);}}

不抛出异常,可以正常获取数据

2024-05-23 23:02:00.506  INFO 10608 --- [nio-8080-exec-1] c.f.m.plugin.MyBatisSqlParsingPlugin     : Execute SQL:
INSERT INTO simple_object  ( id,
name )  VALUES  ( 2,
'name1716476520466' )
2024-05-23 23:02:00.592  INFO 10608 --- [nio-8080-exec-2] c.f.m.plugin.MyBatisSqlParsingPlugin     : Execute SQL:
SELECT id,name FROM simple_object WHERE id=2 
2024-05-23 23:02:00.641  INFO 10608 --- [nio-8080-exec-1] c.f.m.controller.SimpleController        : simpleObject1 (这里会输出simpleObject1):SimpleObject(id=2, name=name1716476520466)

不使用事务(不推荐)

示例代码

import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;import java.util.Objects;@Slf4j
@RestController
@RequestMapping("simple")
@RequiredArgsConstructor
public class SimpleController {private final SimpleObjectMapper simpleObjectMapper;private final RestTemplate restTemplate;/*** 不使用事务,远程调用可以查询到数据。(不推荐)*/@GetMapping("insert3")public void insert3() {SimpleObject simpleObject = new SimpleObject();simpleObject.setId(2);simpleObject.setName("name" + System.currentTimeMillis());simpleObjectMapper.insert(simpleObject);//1、因为没有事务,所以这里会新增数据到数据库SimpleObject simpleObject1 = restTemplate.getForEntity("http://localhost:8080/simple/2", SimpleObject.class, simpleObject.getId()).getBody();log.info("simpleObject1 (这里会输出simpleObject1):{}",simpleObject1);//2.这里会输出id = 2的 SimpleObject 对象,因为事务提交,数据库会新增数据if (Objects.isNull(simpleObject1)) {throw new RuntimeException("simpleObject1 is null");}}/*** 被远程调用的查询方法*/@GetMapping("{id}")public SimpleObject selectById(@PathVariable Integer id) {return simpleObjectMapper.selectById(id);}}

不抛出异常,可以正常获取数据

2024-05-23 23:04:31.889  INFO 10608 --- [nio-8080-exec-6] c.f.m.plugin.MyBatisSqlParsingPlugin     : Execute SQL:
INSERT INTO simple_object  ( id,
name )  VALUES  ( 2,
'name1716476671888' )
2024-05-23 23:04:31.895  INFO 10608 --- [nio-8080-exec-7] c.f.m.plugin.MyBatisSqlParsingPlugin     : Execute SQL:
SELECT id,name FROM simple_object WHERE id=2 
2024-05-23 23:04:31.897  INFO 10608 --- [nio-8080-exec-6] c.f.m.controller.SimpleController        : simpleObject1 (这里会输出simpleObject1):SimpleObject(id=2, name=name1716476671888)

这篇关于解决SpringBoot使用@Transactional进行RestTemplate远程调用导致查询数据记录为null的bug的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!


原文地址:
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.chinasem.cn/article/996965

相关文章

Java如何用乘号来重复字符串的功能

《Java如何用乘号来重复字符串的功能》:本文主要介绍Java使用乘号来重复字符串的功能,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录Java乘号来重复字符串的功能1、利用循环2、使用StringBuilder3、采用 Java 11 引入的String.rep

Mysql数据库中数据的操作CRUD详解

《Mysql数据库中数据的操作CRUD详解》:本文主要介绍Mysql数据库中数据的操作(CRUD),详细描述对Mysql数据库中数据的操作(CRUD),包括插入、修改、删除数据,还有查询数据,包括... 目录一、插入数据(insert)1.插入数据的语法2.注意事项二、修改数据(update)1.语法2.有

Nginx使用Keepalived部署web集群(高可用高性能负载均衡)实战案例

《Nginx使用Keepalived部署web集群(高可用高性能负载均衡)实战案例》本文介绍Nginx+Keepalived实现Web集群高可用负载均衡的部署与测试,涵盖架构设计、环境配置、健康检查、... 目录前言一、架构设计二、环境准备三、案例部署配置 前端 Keepalived配置 前端 Nginx

Python logging模块使用示例详解

《Pythonlogging模块使用示例详解》Python的logging模块是一个灵活且强大的日志记录工具,广泛应用于应用程序的调试、运行监控和问题排查,下面给大家介绍Pythonlogging模... 目录一、为什么使用 logging 模块?二、核心组件三、日志级别四、基本使用步骤五、快速配置(bas

SpringBoot中HTTP连接池的配置与优化

《SpringBoot中HTTP连接池的配置与优化》这篇文章主要为大家详细介绍了SpringBoot中HTTP连接池的配置与优化的相关知识,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一... 目录一、HTTP连接池的核心价值二、Spring Boot集成方案方案1:Apache HttpCl

使用animation.css库快速实现CSS3旋转动画效果

《使用animation.css库快速实现CSS3旋转动画效果》随着Web技术的不断发展,动画效果已经成为了网页设计中不可或缺的一部分,本文将深入探讨animation.css的工作原理,如何使用以及... 目录1. css3动画技术简介2. animation.css库介绍2.1 animation.cs

Spring Boot项目打包和运行的操作方法

《SpringBoot项目打包和运行的操作方法》SpringBoot应用内嵌了Web服务器,所以基于SpringBoot开发的web应用也可以独立运行,无须部署到其他Web服务器中,下面以打包dem... 目录一、打包为JAR包并运行1.打包为可执行的 JAR 包2.运行 JAR 包二、打包为WAR包并运行

Java进行日期解析与格式化的实现代码

《Java进行日期解析与格式化的实现代码》使用Java搭配ApacheCommonsLang3和Natty库,可以实现灵活高效的日期解析与格式化,本文将通过相关示例为大家讲讲具体的实践操作,需要的可以... 目录一、背景二、依赖介绍1. Apache Commons Lang32. Natty三、核心实现代

使用雪花算法产生id导致前端精度缺失问题解决方案

《使用雪花算法产生id导致前端精度缺失问题解决方案》雪花算法由Twitter提出,设计目的是生成唯一的、递增的ID,下面:本文主要介绍使用雪花算法产生id导致前端精度缺失问题的解决方案,文中通过代... 目录一、问题根源二、解决方案1. 全局配置Jackson序列化规则2. 实体类必须使用Long封装类3.

Spring Boot 常用注解整理(最全收藏版)

《SpringBoot常用注解整理(最全收藏版)》本文系统整理了常用的Spring/SpringBoot注解,按照功能分类进行介绍,每个注解都会涵盖其含义、提供来源、应用场景以及代码示例,帮助开发... 目录Spring & Spring Boot 常用注解整理一、Spring Boot 核心注解二、Spr