如何在SimpleJpaRepository中禁用读操作的事务行为?

18 浏览
0 Comments

如何在SimpleJpaRepository中禁用读操作的事务行为?

我们有一个Spring Boot应用程序,它在执行数据库CRUD操作时,大量依赖于SimpleJpaRepository实现。

问题:该类使用@Transactional注释,导致所有被调用的方法都被包装在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个(BAD):

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

admin 更改状态以发布 2023年5月24日
0
0 Comments

您是否尝试使用以下方法进行注释

@Transactional(propagation = Propagation.NOT_SUPPORTED)

Execute non-transactionally, suspend the current transaction if one exists. Analogous to EJB transaction attribute of the same name.

相关文档在此处

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

  2. 所以你的选择是重新定义findBy方法,并带上@Transactional(propagation=SUPPORTS)注解。

  3. 这样做不会破坏任何东西,但会禁用一些优化。请参考由Spring Data作者Oliver Gierke回答的答案。

像findAll()和findOne(…)这样的读取方法使用@Transactional(readOnly=true),虽然这并不是严格必要的,但会在事务基础设施中触发一些优化(将FlushMode设置为MANUAL,使持久化提供程序在关闭EntityManager时跳过脏检查)。除此之外,该标志也设置在JDBC连接上,从而在该级别上实现了更多的优化。

0