Hibernate需要失败才能下次成功



我正在编写两个方法来重新初始化应用程序中的数据库。首先应该动态列出所有表,然后截断它们。第二个负责数据的重新填充。

截断方法使用本机查询:

public void truncate() throws Exception {
List<String> names = getAllTableNames();
names.forEach(tableName -> {
entityManager.createNativeQuery("TRUNCATE TABLE " + tableName + " CASCADE").executeUpdate();
});
//        entityManager.setFlushMode(FlushModeType.COMMIT);
//        entityManager.getEntityManagerFactory().getCache().evictAll();
entityManager.flush();
}

数据重新初始化的第二种方法只是解析一些文档,创建实体并批量保存它们。

这两种方法都位于标记为@Transactional的服务中。我有两个端点可以分别调用它们。

现在发生的情况是,在我截断表(无错误结束)后,我调用re-init,得到:

WARNING: org.springframework.dao.DataIntegrityViolationException: A different object with the same identifier value was already associated with the session : [com.nws.vedica.model.entity.DocType#ACCOUNTCONTRACTCANCEL]; nested exception is javax.persistence.EntityExistsException: A different object with the same identifier value was already associated with the session : [com.nws.vedica.model.entity.DocType#ACCOUNTCONTRACTCANCEL]

就好像这些实体仍然存在于EM的高速缓存中一样。

在EM的高速缓存(注释行)之后逐出之后也会发生同样的情况。

现在有两个观察结果:

1.-重新创建实体的第二个请求总是成功的。

2.-recreate请求是成功的RIGHT AFTER truncate操作,如果我运行两次重新创建(第一次成功,第二次失败),然后truncate,然后重新创建--非常严重的

请指导我发生了什么以及如何使其正常工作。

谢谢!

编辑:

我注意到打电话给后

truncateDatabaseSrv.truncate();

当我试图查询集合时程序挂起:

List<DocType> docTypes = docTypeDAO.getAllDocTypes();

所以我放了

entityManager.createNativeQuery("COMMIT;").executeUpdate();

进入truncate方法。

现在它不会挂起,并将按预期返回空数组。但是,当我在下一个请求中调用DocType集合re-init时,我仍然会得到与上面提到的相同的错误。

此外,我注意到在截断后正在进行diry检查:

2:05:04,200 DEBUG AbstractFlushingEventListener:132 - Processing flush-time cascades
12:05:04,202 DEBUG AbstractFlushingEventListener:174 - Dirty checking collections
12:05:04,203 DEBUG Collections:189 - Collection found: [com.nws.vedica.model.entity.DocType.fieldValidities#ACCOUNTCONTRACTCANCEL], was: [com.nws.vedica.model.entity.DocType.fieldValidities#ACCOUNTCONTRACTCANCEL] (initialized)
12:05:04,203 DEBUG Collections:189 - Collection found: [com.nws.vedica.model.entity.DocType.keywords#ACCOUNTCONTRACTCANCEL], was: [com.nws.vedica.model.entity.DocType.keywords#ACCOUNTCONTRACTCANCEL] (initialized)
12:05:04,204 DEBUG Collections:189 - Collection found: [com.nws.vedica.model.entity.DocType.fieldValidities#ACCOUNTDEBTSLIENCONTRACT], was: [com.nws.vedica.model.entity.DocType.fieldValidities#ACCOUNTDEBTSLIENCONTRACT] (initialized)

(initialized)对我来说似乎很可疑,但这就是我这次所要做的。。。

我不确定你是怎么做的,所以我在这里做了一些假设,并提出了一些建议。

我使用的是Spring/hibernate,我的事务注释出现在springbean上的两个业务方法上。类似这样的东西-

@Transactional(readOnly = false, propagation = Propagation.REQUIRED, rollbackFor = Exception.class, isolation = Isolation.DEFAULT)

在第一个spring方法返回后,事务被提交,因为它是容器管理的(而不是用户管理的,我认为这里是这样)。然后返回控制器并调用同一服务中的另一个方法。

如果你不想回到你的控制器,那么我建议在你的第二个方法上有这个注释,并从第一个方法调用它(或者无论你管理交易的方式如何)-

@Transactional(readOnly = false, propagation = *Propagation.REQUIRES_NEW*, rollbackFor = Exception.class, isolation = Isolation.DEFAULT)

我认为这应该奏效。值得一试。

相关内容

最新更新