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

3
我们有一个Spring Boot应用程序,它严重依赖于SimpleJpaRepository实现来执行数据库CRUD操作。
问题:该类带有@Transactional注释,导致调用的所有方法都被包装在SQL事务中。
我们希望我们的存储库仅为插入/更新/删除操作生成SQL事务,而不是选择操作(除非它们是从另一个使用@Transactional注释的方法调用的)。
我们如何设置我们的存储库以实现此目的,并且会有哪些不太明显的影响? (我假设该类之所以带有这样的注释是有原因的)
代码和日志
调用 @Transactional 方法,期望 1 个事务,发现 1 个 (OK)
@Transactional
public User readUser(int id){
    userRepository.findOne(id);
    roleRepository.findByUser(id);
}

SQL Profiler:
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 Profiler:

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

我不希望它抛出异常。我希望它简单地不为我们进行的每个查询创建隐式事务。添加详细日志。 - Alexandru Severin
你的仓库方法是如何实现的?它们使用Spring Data Repos吗? - Kavithakaran Kanapathippillai
你是否希望对于未注释的方法根本不进行任何事务处理? - Xaero Degreaz
@KavithakaranKanapathippillai 所有的代码库都实现了Spring Data JPA的SimpleJpaRepository - Alexandru Severin
是的,这就是我想要澄清的原因。SimpleJpaRepository 中实现的方法都有 Transactional 注解。 - Kavithakaran Kanapathippillai
显示剩余6条评论
2个回答

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

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

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

像findAll()和findOne(...)这样的读取方法使用@Transactional(readOnly = true) 并不是必须的,但会在事务基础设施中触发一些优化(将FlushMode设置为MANUAL,以便持久性提供者在关闭EntityManager时可能跳过脏检查)。除此之外,该标志还设置在JDBC连接上,从而在该级别上进行进一步的优化。

我假设如果您需要执行多个findBy操作以获得可重复读取性,那么您将在服务层中使用@Transactional(readOnly=true)进行包装。 - Kavithakaran Kanapathippillai
一个稍微简单的解决方案是使用@EnableJpaRepositories(enableDefaultTransactions = false)。这将禁用begin/commit SQL语句,但仍将实例绑定到当前线程的TransactionInfo(请参见TransactionAspectSupport.prepareTransactionInfo()的最后一条语句),因此在调用没有包装事务的方法时不会抛出javax.persistence.TransactionRequiredException: no transaction is in progress异常。 - Siggen

0

你尝试过给所需的方法添加注释吗?

@Transactional(propagation = Propagation.NOT_SUPPORTED)

非事务性执行,如果存在当前事务,则暂停当前事务。类似于同名的EJB事务属性。

此处有文档


这将暂停由@Transactional创建的已存在的显式事务,而我不想这样做。我只想停止隐式事务。 - Alexandru Severin

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接