我正在使用 JPA 2 Hibernate 实现和 Spring MVC 来管理事务
我正在使用通用 DAO 模式来管理数据库操作
目前,我们有一个单一方法的事务,例如:
someDao.save (someObject)
它是一个从 JSF 页面调用的 @Transactional
方法。
save方法继承自Generic DAO,它持久化了多个实体的数据库,具有级联的oneToMany关系,但是它要在数据库中执行几千条插入语句,所以耗时很长。
我想为用户提供一种取消操作的方法,但到目前为止,我无法做到这一点,当我调用方法 save() 时,直到所有插入都完成后才能取消执行。
我试图抛出一些异常,从注入(inject)的 PersistenceContext 回滚事务,但它没用,它只是没有错误地完成:(
显然,我不能从方法中抛出异常,它只是来 self 的源的一次调用。 JPA PersistenceContext 做一切
有没有办法取消操作并强制回滚?
最佳答案
保存 1000 个实体应该不会花那么长时间。确保您受益于 JDBC batching :
- 您需要使用非 IDENTITY 的实体标识符。 IDENTITY 禁用批处理。 SEQUENCE 和 TABLE 生成器允许批处理。
设置以下 hibernate 属性:
<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"/>
如果你想让保存操作超时,你需要在你的服务方法中添加注释:
这样在 30 秒后您的保存事务将超时并抛出异常,回滚所有插入。
批处理
如果您想取消批量插入操作,同时允许已处理的项目继续进行,那么您需要选择批量处理。
您需要将所有项目拆分成 block 并分批插入。为此,我将批处理开始和批处理结束边界与实际批处理线程分开。因此,虽然批处理开始和批处理结束由 Web 请求触发,但批处理由专用的 ExecutorService 运行。 .
这样你就可以:
- 同时处理批处理
- 立即停止所有批处理,使用shutdownNow
因为查询执行是I/O阻塞操作,所以需要支持线程中断,当批处理结束线程中断批处理执行器时,可以通知你停止处理下一批并尽快退出。
我会使用一个单独的 ExecutionService
关于java - 使用 Spring 时如何手动取消 JPA 或 Hibernate 事务,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25633085/