首页 > 解决方案 > 如何禁用来自 SimpleJpaRepository 的读取操作的事务行为?

问题描述

我们有一个 Spring Boot 应用程序,它严重依赖SimpleJpaRepository实现来执行数据库 CRUD 操作。

问题:该类使用 注释@Transactional,导致所有调用的方法都包装在 SQL 事务中。

我们希望我们的存储库只为插入/更新/删除操作生成 SQL 事务,而不是为选择操作生成 SQL 事务(除非它们是从另一个用 注释的方法调用的@Transactional

我们如何设置我们的存储库来实现这一点,什么是不太明显的效果?(我认为这个类被这样注释是有原因的)


代码和日志

调用 @Transactional 方法,预期 1 个事务,找到 1 个(OK)

@Transactional
public User readUser(int id){
    userRepository.findOne(id);
    roleRepository.findByUser(id);
}

SQL 探查器:

set implicit_transactions on 
exec sp_executesql N'select userentity0_.id as id1_45_, .....'
exec sp_executesql N'select roleassign0_.id as id1_36_, ....'
IF @@TRANCOUNT > 0 COMMIT TRAN

没有@Transactional,预计没有交易,发现2,由存储库(坏)创建:

public User readUser(int id){
    userRepository.findOne(id);
    roleRepository.findByUser(id);
}

SQL 探查器:

set implicit_transactions on 
exec sp_executesql N'select userentity0_.id as id1_45_, .....'
IF @@TRANCOUNT > 0 COMMIT TRAN

set implicit_transactions on 
exec sp_executesql N'select roleassign0_.id as id1_36_, ....'
IF @@TRANCOUNT > 0 COMMIT TRAN

标签: javasql-serverspringspring-boottransactions

解决方案


  1. 默认情况下,存储库实例上的 CRUD 方法是事务性的。对于读取操作,事务配置 readOnly 标志设置为 true。

  2. 因此,您的选择是使用)重新定义findBy方法@Transactional(propagation=SUPPORTS

  3. 这样做并没有破坏任何东西,而是禁用了一些优化。请参阅 Spring Data 作者 Oliver Gierke 的回答

像 findAll() 和 findOne(...) 这样的读取方法正在使用 @Transactional(readOnly = true)这不是绝对必要的,但会触发事务基础结构中的一些优化(将 FlushMode 设置为 MANUAL 以让持久性提供者在关闭时可能跳过脏检查实体管理器)。除此之外,该标志也在 JDBC 连接上设置,这会导致该级别的进一步优化。


推荐阅读