java - 如何禁用来自 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
解决方案
默认情况下,存储库实例上的 CRUD 方法是事务性的。对于读取操作,事务配置 readOnly 标志设置为 true。
因此,您的选择是使用)重新定义
findBy
方法@Transactional(propagation=SUPPORTS
这样做并没有破坏任何东西,而是禁用了一些优化。请参阅 Spring Data 作者 Oliver Gierke 的回答
像 findAll() 和 findOne(...) 这样的读取方法正在使用 @Transactional(readOnly = true)这不是绝对必要的,但会触发事务基础结构中的一些优化(将 FlushMode 设置为 MANUAL 以让持久性提供者在关闭时可能跳过脏检查实体管理器)。除此之外,该标志也在 JDBC 连接上设置,这会导致该级别的进一步优化。
推荐阅读
- c# - 如何通过 ILogger 将日志写入 EventLog
在 Asp.net 核心? - objective-c - Sanboxed 应用程序,通过引用包含文件?
- javascript - 继承的原型函数不是函数
- python - 如何为 Graphviz 中的每个节点添加标签?
- sockets - 如何使用 Golang 在 IP 标头中为 TCP 连接设置 ToS 字段
- windows - 使用批处理脚本在文本文件中的特定行号处插入文本
- tableau-api - 将 x 误差线添加到 tableau 中的散点图
- python-3.x - 如何使用 pm2 运行 python3 脚本
- javascript - Dom 操作与 ajax 请求上的 javascript 代码不同步?
- xamarin.forms - Signal R 大约需要 1 分钟才能连接到移动网络 Xamarin 形式的 Hub