如何在SimpleJpaRepository中禁用读操作的事务行为?
如何在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
您是否尝试使用以下方法进行注释
@Transactional(propagation = Propagation.NOT_SUPPORTED)
Execute non-transactionally, suspend the current transaction if one exists. Analogous to EJB transaction attribute of the same name.
-
默认情况下,仓库实例上的CRUD方法是事务性的。对于读操作,事务配置readOnly标志被设置为true。
-
所以你的选择是重新定义
findBy
方法,并带上@Transactional(propagation=SUPPORTS
)注解。 -
这样做不会破坏任何东西,但会禁用一些优化。请参考由Spring Data作者Oliver Gierke回答的答案。
像findAll()和findOne(…)这样的读取方法使用@Transactional(readOnly=true),虽然这并不是严格必要的,但会在事务基础设施中触发一些优化(将FlushMode设置为MANUAL,使持久化提供程序在关闭EntityManager时跳过脏检查)。除此之外,该标志也设置在JDBC连接上,从而在该级别上实现了更多的优化。