【问题标题】:Hibernate needs to fail in order to succeed next timeHibernate 需要失败才能下一次成功
【发布时间】:2017-10-06 18:43:24
【问题描述】:

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

Truncate 方法使用原生查询:

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.- 如果我运行重新创建两次(第一次成功,第二次失败)然后截断然后重新创建,则重新创建请求在截断操作之后成功。 --很奇怪

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

谢谢!

编辑:

我注意到打电话后

            truncateDatabaseSrv.truncate();

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

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

所以我放了

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

进入截断方法。

现在它不会挂起,会按预期返回空数组。但是当我在下一个请求中调用 DocType 集合重新初始化时,我仍然得到与上述相同的错误。

我还注意到截断后正在进行 diry-checking:

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) 对我来说似乎很可疑,但这就是我这次的全部内容......

【问题讨论】:

  • 我对 Hibernate 生疏了...您是否尝试过类似的方法: entityManager.getTransaction().commit() ?
  • 一旦您尝试获取交易表单 em,它就会失败。在截断操作之前。错误说,tx 已经被管理..(我想通过@Transactional 注释)

标签: java hibernate jpa transactions nativequery


【解决方案1】:

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

我使用的是 Spring/hibernate,并且我的事务注释出现在 spring bean 的两个业务方法中。像这样 -

@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)

我认为这应该可行。值得一试。

【讨论】:

  • 同样的事情发生了。为了清楚起见,我分别调用 truncate 和 re-init 。截断请求结束后,我可以看到数据库已清除,所以它可以工作......这是关于实体管理器的东西,让他认为我仍然有 tat 数据
  • Hmm.. 如果您已经从您最喜欢的 sql 客户端中看到数据库是清晰的,那么我会说这可能是您的重新种子脚本或 java 代码中的错误。看起来您(或休眠)将相同的 PK 分配给多个对象。只是预感。
  • 我没有使用种子脚本。第二次调用该服务应该重新设置它。它第一次失败了。在第二个工作。我不确定你是否明白我的意思。我还应该向您展示什么?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-10-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多