大数跨境
0
0

性能优化!3种场景下使用@Transactional对性能影响太大了

性能优化!3种场景下使用@Transactional对性能影响太大了 Spring全家桶实战案例
2025-09-29
0
导读:性能优化!3种场景下使用@Transactional对性能影响太大了
Spring Boot 3实战案例锦集PDF电子书已更新至130篇!
图片

🎉🎉《Spring Boot实战案例合集》目前已更新177个案例,我们将持续不断的更新。文末有电子书目录。

💪💪永久更新承诺

我们郑重承诺,所有订阅合集的粉丝都将享受永久免费的后续更新服务

💌💌如何获取
订阅我们的合集点我订阅,并通过私信联系我们,我们将第一时间将电子书发送给您。

→ 现在就订阅合集

环境:SpringBoot3.4.2



1. 简介

@Transactional 是 Spring 中用于声明式事务管理的核心注解,旨在简化数据库事务操作。在传统的编程式事务中,我们需手动编写事务的开启、提交或回滚代码,而通过 @Transactional 注解将事务逻辑与业务代码解耦。只需在方法或类上添加该注解,Spring 会基于 AOP(面向切面编程)自动拦截调用,在方法执行前开启事务,执行后根据异常情况提交或回滚。这种设计显著提升了代码的可读性和可维护性。

但如果滥用@Transactional,会对系统性能产生显著负面影响,主要体现在以下几个方面:

  • 过度使用会导致事务范围过大,延长数据库连接占用时间,增加锁竞争和死锁风险

  • 不必要的细粒度事务会引发频繁的提交和回滚操作,加重数据库负载

  • 在非关键数据操作或只读场景中滥用事务,会无谓消耗系统资源,降低整体吞吐量。

本篇文章会介绍基于 JPA 和 JDBC 时,@Transactional 注解对查询性能的影响。

纯查询到底要不要事务?

2.实战案例

2.1 准备环境

配置文件

spring:  datasource:    driverClassName: com.mysql.cj.jdbc.Driver    url: jdbc:mysql://localhost:3306/batch    username: root    password: 123123    type: com.zaxxer.hikari.HikariDataSource    hikari:      minimumIdle: 10      maximumPoolSize: 10---spring:  jpa:    generateDdl: false    hibernate:      ddlAuto: update    openInView: true    show-sqlfalse      

创建实体对象

@Entity@Table(name = "o_user")public class User {  @Id  @GeneratedValue(strategy = GenerationType.IDENTITY)  private Integer id ;  private String name ;  private Integer age ;  private String phone ;  private String sex ;  // getters, setters}

准备接口

@GetMapping("")public ResponseEntity<?> query() {  return ResponseEntity.ok(this.userService.queryUser()) ;}

准备数据(500w)

2.1 使用Repository查询测试

测试1,不使用@Transactional注解

private final UserRepository userRepository ;public User queryUser() {  return this.userRepository.findById(4888888).orElse(null) ;}

使用JMeter测试结果如下:

吞吐量平均:9700

测试2,使用@Transactional

@Transactionalpublic User queryUser() {}

使用JMeter测试结果如下:

吞吐量平均:12700

这是否打破了你原有的认知呢?按照常规理论,使用 @Transactional 注解通常会使性能变差,然而当前呈现的数据却表明,使用该注解后性能反而有所提升。

测试3,使用只读事务

@Transactional(readOnly = true)public User queryUser() {}

使用JMeter测试结果如下:

吞吐量平均:9300

该结果与不使用注解相差不大。

思考:为什么使用了@Transactional注解反而性能更高呢?欢迎大家留言讨论。

2.3 使用JDBC查询

测试1,不使用@Transactional注解

private final JdbcTemplate jdbcTemplate ;public User queryUser() {  return this.jdbcTemplate.queryForObject("select id, name, age, phone, sex from o_user where id = 4888888"new RowMapper<User>() {    @Override    public User mapRow(ResultSet rs, int rowNum) throws SQLException {      User user = new User() ;      user.setId(rs.getInt("id")) ;      user.setAge(rs.getInt("age")) ;      user.setName(rs.getString("name")) ;      user.setPhone(rs.getString("phone")) ;      user.setSex(rs.getString("sex")) ;      return user ;    }  }) ;}

JMeter测试结果:

吞吐量平均:25000

JPA是简单了,代价就是性能太差了。

测试2,使用@Transactional注解

@Transactionalpublic User queryUser() {}

JMeter测试结果:

吞吐量平均:13100

这倒是符合我们的预期,使用了@Transactional注解性能明显下降。

测试3,使用只读事务

@Transactional(readOnly = true)public User queryUser() {}

JMeter测试结果:

同样符合预期,与读写事务差不多。

2.4 使用EntityManager查询

测试1,不使用@Transactional注解

private final EntityManager em ;public User queryUser() {  return this.em.find(User.class4888888) ;}

JMeter测试结果:

吞吐量平均:24000

测试2,使用@Transactional注解

@Transactionalpublic User queryUser() {  return this.em.find(User.class4888888) ;}

JMeter测试结果:

吞吐量平均:13000

测试3,使用只读事务

@Transactional(readOnly = true)public User queryUser() {}

JMeter测试结果:

吞吐量平均:9800

2.5 性能柱状图

2.6 查询使用事务总结

  • 保证一致性:在一个事务中,所有查询看到的是同一时间点的数据快照(取决于隔离级别),避免了中途数据被其他事务修改导致的不一致

  • 性能优化:Spring 提供 @Transactional(readOnly = true),明确标记为只读事务。这可以让底层数据库(如 Oracle、MySQL InnoDB)进行优化,例如启用只读快照、减少锁竞争等。

  • 连接复用:在一个事务中的多个操作可以复用同一个数据库连接,减少连接创建/释放开销。

  • 与写操作兼容:如果将来该查询方法被包含在一个更大的写事务中,有 @Transactional 可以无缝集成。

如下多个查询使用事务保证了同一时间点的数据:

private final UserRepository userRepository ;private final OrderRepository orderRepository ;
@Transactional(readOnly = true)public UserInfoDto getUserInfo(Long userId) {  User user = userRepository.findById(userId);  List<Order> orders = orderRepository.findByUserId(userId);  return new UserInfoDto(user, orders);}




以上是本篇文章的全部内容,如对你有帮助帮忙点赞+转发+收藏

JSON处理不再头疼!Jackson Tree模型解锁JSON操作的开挂模式

8种测试方法,让 Spring Boot 接口稳定性提升 200%

高级开发!自定义注解100行代码实现 @Resource/@Autowired 注入功能

性能优化!3种方法优化@Transactional长事务问题,方法三性能提升4倍(不修改业务代码)

技术专家!Spring Boot 一个注解动态切换实现类

性能狂飙!Spring Boot 基于注解的 8 个缓存应用技巧

强大!Spring Boot 一个注解导出任意Excel

@JsonFormat 只会转日期?这4个高能用法太强大了

Spring AI + LangGraph4j 多智能体开发,太强大了!

真心强大!Spring AI + MCP 智能体工具动态更新

真强!使用JSON文件作为Spring Boot配置属性

高级开发!一个注解动态控制Controller接口,支持实时更新

图片
图片
图片
图片
图片
图片
图片
图片
图片

【声明】内容源于网络
0
0
Spring全家桶实战案例
Java全栈开发,前端Vue2/3全家桶;Spring, SpringBoot 2/3, Spring Cloud各种实战案例及源码解读
内容 832
粉丝 0
Spring全家桶实战案例 Java全栈开发,前端Vue2/3全家桶;Spring, SpringBoot 2/3, Spring Cloud各种实战案例及源码解读
总阅读195
粉丝0
内容832