【问题标题】:How to disable Transactional behaviour for read operations from SimpleJpaRepository?如何禁用来自 SimpleJpaRepository 的读取操作的事务行为?
【发布时间】:2020-10-24 10:15:00
【问题描述】:

我们有一个 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,由存储库创建 (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

【问题讨论】:

  • 您是否从类或方法中调用这些方法,并使用事务性注释?您可以使用事务性注释其中一种方法来测试它,并将传播级别设置为NEVER 。如果你从事务中调用它,它会抛出一个异常。
  • 我不希望它抛出异常。我希望它不会为我们所做的每个查询创建一个隐式事务。添加详细日志
  • 您的存储库方法是如何实现的?他们使用弹簧数据存储库吗?
  • 您是否根本不希望非注释方法的任何事务?
  • @KavithakaranKanapathippillai 所有存储库都从 spring-data-jpa 实现 SimpleJpaRepository

标签: java sql-server spring spring-boot transactions


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

  2. 所以您的选择是用@Transactional(propagation=SUPPORTS 重新定义findBy 方法

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

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

【讨论】:

  • 我假设如果您必须执行多个 findBy 操作,以获得可重复读取,您将在服务层中将它们包装在 @Transactional(readOnly=true) 中
【解决方案2】:

您是否尝试过用

注释所需的方法
@Transactional(propagation = Propagation.NOT_SUPPORTED)

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

Docs here

【讨论】:

  • 这将暂停由@Transactional 创建的已经存在的显式事务,我不希望这样。我只想停止隐式交易
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2013-08-29
  • 1970-01-01
  • 2013-12-12
  • 2021-07-13
  • 1970-01-01
  • 1970-01-01
  • 2012-05-31
相关资源
最近更新 更多