java - 关于何时使用 spring/hibernate 为批处理作业启动新 session 或事务的最佳实践是什么?

标签 java hibernate spring session transactions

我在 Java 中有一组调用我的服务类的批处理/cron 作业。我也在使用 Hibernate 和 Spring。

最初批处理层总是创建一个外部事务,然后批处理作业将调用一个服务以从具有相同 session 的数据库中获取对象列表,然后调用一个服务来分别处理每个对象。我的服务层有一个 tx-advice 集,可以在任何 throwable 上回滚。因此,如果第 5 个对象出现异常,则处理的前 4 个对象也会回滚,因为它们都是同一事务的一部分。

所以我认为在批处理层中创建的这个外部事务是不必要的。我删除了它,现在我调用服务来获取对象列表。然后调用另一个服务来分别处理每个对象,如果其中一个对象失败,其他对象仍将存在,因为它是每个服务调用的新事务/ session 。但是我现在遇到的问题是在获取对象列表之后,当我将每个对象传递给服务进行处理时,如果我尝试获取其中一个属性,我会收到延迟初始化错误,因为 session 用于加载该对象(来自列表)已关闭。

我想到的一些选项是在批处理作业中获取 ID 列表并将每个 ID 传递给服务,服务将在该 session 中检索整个对象并对其进行处理。另一种方法是将该对象的属性的延迟加载设置为 false,但这会每次都加载所有内容,即使有时不需要嵌套属性也是如此。

我总是可以回到原来的方式,每个批处理作业都有外部事务,然后在每次调用服务处理每个单独对象之前在批处理作业中创建另一个事务...

对于这样的事情,最佳做法是什么?

最佳答案

嗯,我会说你列出了所有可能的选项,除了 OpenSessionInView .这将使您的 session 在事务中保持 Activity 状态,但很难正确实现。如此困难以至于被 many 视为反模式.

但是,由于您没有实现 Web 界面,也没有处理高度线程化的环境,所以我会说这是可行的方法。这不像您将实体传递给 View 。您最大的恐惧是在遍历集合时对数据库进行 N+1 调用,但由于这是一项 cron 作业,与代码整洁度相比,性能可能不是主要问题。如果您真的担心它,请确保通过调用可以执行选择 * 的 DAO 获得所有 Collection 。

此外,当您之前在同一个事务中执行所有操作时,您实际上是在 View 中执行打开 session 。在 Spring 中,Session 是在每个事务的基础上打开的,因此长时间保持事务打开与保持 Session 长时间打开实际上是一样的。你的情况唯一真正的区别是你可以定期提交而不用担心在路上出现惰性初始化错误。

编辑

综上所述,在 View 中设置 Open Session 需要一些时间,因此除非您对在同一事务中执行所有操作有任何特殊问题,否则您可能会考虑回到那个。

另外,我刚刚注意到您提到在批处理层中打开一个事务,然后在服务层中打开“迷你事务”。最重要的是,这不是一个好主意。 Spring 的注释驱动事务将搭载在 session 中任何当前打开的事务上。这意味着如果当前打开的事务是可读写的,那么本来应该是只读的事务会突然变成可读写的。此外,Session 在最外层事务完成之前不会被刷新,因此使用 @Transactional 标记服务层没有意义。将 @Transactional 放在多层上只会给人一种错误的安全感。

我其实blogged about this issue前段时间。

关于java - 关于何时使用 spring/hibernate 为批处理作业启动新 session 或事务的最佳实践是什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5332658/

相关文章:

java - Spring Entity使用Service,可能存在设计缺陷,但还是

java - 在 Java 中调用不带括号的新对象的方法 : order of operations violation?

java - 从 Java 运行 unix 命令 - 身份验证失败

java - Spring依赖注入(inject)不适用于继承

eclipse - Gradle和Eclipse的Hibernate映射文件路径

Java - = 运算符不适用于 `@Controller` 中的类

java - LibGDX - 将跨平台客户端连接到服务器(HTML5/GWT、iOS、Android 和桌面)

javac 未显示在 .bat 文件中

java - JPA EntityManager 未注入(inject) Java EE 应用程序

java - 无法执行目标 org.apache.maven.plugins :maven-enforcer-plugin