【问题标题】:How to manually cancel a JPA or Hibernate transaction when using Spring使用 Spring 时如何手动取消 JPA 或 Hibernate 事务
【发布时间】:2014-09-02 22:02:18
【问题描述】:

我正在使用 JPA 2 Hibernate 实现和 Spring MVC 来管理事务

我正在使用通用 DAO 模式来管理数据库操作

目前,我们有一个单一方法的事务,例如:

someDao.save (someObject)

这是一个从 JSF 页面调用的 @Transactional 方法。

save方法继承自Generic DAO,它持久化到数据库中具有级联oneToMany关系的许多实体,但它必须在数据库中执行大约1000条insert语句,因此需要很长时间。

我想为用户提供一种取消操作的方法,但到目前为止,我无法做到这一点,当我调用方法 save() 时,直到所有插入都完成后才能取消执行。

我试图抛出一些异常,从注入的 PersistenceContext 回滚事务,但它没用,它只是完成而没有错误:(

显然,我不能从方法中抛出异常,这只是来自我的源的一次调用。 JPA PersistenceContext 无所不能

有没有办法取消操作并强制回滚?

【问题讨论】:

    标签: java spring hibernate jpa transactions


    【解决方案1】:

    保存 1000 个实体应该不会花那么长时间。确保您从JDBC batching 中受益:

    1. 您需要使用不是 IDENTITY 的实体标识符。 IDENTITY 禁用批处理。 SEQUENCE 和 TABLE 生成器允许批处理。
    2. 设置以下休眠属性:

      <property name="hibernate.order_updates" value="true"/>
      <property name="hibernate.order_inserts" value="true"/>
      <property name="hibernate.jdbc.batch_versioned_data" value="true"/>
      <property name="hibernate.jdbc.fetch_size" value="50"/>
      <property name="hibernate.jdbc.batch_size" value="520"/>
      
    3. 如果你想使保存操作超时,你需要在你的服务方法上注解:

    这样,在 30 秒后,您的保存事务将超时并抛出异常,回滚您的所有插入。


    批处理

    如果您想取消批量插入操作,同时允许已处理的项目继续进行,那么您需要选择批量处理。

    您需要将所有项目拆分成块并分批插入。为此,我将批处理开始和批处理结束边界与实际批处理线程分开。因此,虽然批处理开始和批处理结束是由 Web 请求触发的,但批处理由专用的ExecutorService 运行。

    这样你可以:

    • 同时处理批次
    • 立即停止所有批处理,使用shutdownNow

    由于查询执行是I/O阻塞操作,需要支持线程中断,所以当批处理端线程中断批处理执行器时,可以通知您停止处理下一个批处理并尽快退出。

    我会使用单独的 ExecutionService

    【讨论】:

    • 谢谢,好吧,我说了大约 1000 个实体,不确定有多少,但在我所做的测试中,它可能是 25000 左右,我们期望更多,这取决于数据,它这样做需要一些时间,而且,我不想自动终止交易,而是手动按下按钮取消或类似的东西,但到目前为止我无法做到这一点。
    • 我用批处理设计提案更新了我的回复。
    • 为了避免这个 Spring+Hibernate BUG,你必须再增加 1 秒的超时时间,即如果你想要 2 秒的超时时间,设置 timeout=3:hibernate.atlassian.net/browse/HHH-9482
    【解决方案2】:

    也许这会对你有所帮助:
    http://docs.jboss.org/hibernate/orm/3.5/javadocs/org/hibernate/Session.html#cancelQuery()

    HibernateSession提供了一个cancelQuery-方法,可以用来取消当前的查询。
    注意:在查询真正终止之前可能需要一些时间。

    【讨论】:

    • 谢谢,我会试试这个,尽管我可以认为如果我的系统被多个用户使用,我最终可能会杀死其他人的事务,我错了吗?谢谢
    • @Makhz HibernatSession#cancelQuery 方法是按会话进行的,一般来说会话是按 JTA 事务或线程分配的,因此除非您有一些其他不寻常的配置,否则它不会杀死其他人的事务。跨度>
    猜你喜欢
    • 2023-02-26
    • 2015-03-26
    • 2011-08-22
    • 2011-08-14
    • 2012-04-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多