【问题标题】:JPA model validation and transaction handlingJPA 模型验证和事务处理
【发布时间】:2012-01-21 05:21:53
【问题描述】:

我目前正在重构一个已经使用 JPA 的应用程序,但 JPA EnitytManager(和事务)目前仅限于 DAO 层。还有一个存储库层和一个服务层。我想让服务层具有事务性,并在服务层上为每个请求提供一个 EntityManger。理想情况下,我不希望我的服务或存储库层了解有关 JPA 的任何信息。

目前,存储库和服务层使用从 DAO 层获得的分离实体。对模型进行更改,并将实体合并回 DAO 层。在新结构中,实体在整个请求期间保持受管理状态,并且 1 个请求包含在 1 个事务中。更改会在事务结束时自动提交。这似乎更符合 JPA 的精神,并且在最常见的情况下运行良好。

有时,尽管对模型进行了更改,然后验证了模型。如果模型不再有效,则不应保存更改。在旧结构中,这很简单:

在这个例子中,流程基本上是一个图,整个图必须验证,没有自引用,每个节点都必须是可达的,第一个节点有一些特殊要求,需要有一个最终节点等等。我们首先对模型进行更改,然后验证模型。

Repository 层代码旧:

changeProcessModel();
messages = ProcessValidator.validate(process);
if (messages.hasNoErrors()) {
    processDao.merge(process);
    messages.addInfoMessage("Process was updated succesfully");
}
return messages;

在新结构中,我认为我有三个选择,我想知道哪一个被认为是最佳做法,或者是否还有其他选择。

新代码选项 1:

changeProcessModel();
messages = ProcessValidator.validate(process);
if (messages.hasNoErrors()) {
    messages.addInfoMessage("Process was updated succesfully");
} else {
    throw new InvalidProcessException(messages);
}
return messages;

此代码有点滥用RuntimeException 来验证某些业务规则。我不认为这被认为是最佳实践,但事务是回滚的。这似乎也与例如 Bean Validation 兼容,如果实体未验证,它也会引发异常。

新代码选项 2:

changeProcessModel();
messages = ProcessValidator.validate(process);
if (messages.hasNoErrors()) {
    messages.addInfoMessage("Process was updated succesfully");
} else {
    em.getTransactionManager.rollback();
}
return messages;

此代码直接在 JPA TransactionManager 上进行回滚,并在我的存储库层和 JPA 之间引入了依赖关系。

新代码选项 3:

changeProcessModel();
messages = ProcessValidator.validate(process);
if (messages.hasNoErrors()) {
    messages.addInfoMessage("Process was updated succesfully");
} else {
    processDao.refresh(process);
}
return messages;

这段代码看起来很不错,但它确实依赖于CascadeType.REFRESH 在需要刷新的进程实体关系上正确设置。

例如,我也可以使用processDao.clear(); 或processDao.rollback();,但这会将processDao 的范围扩大到整个entityManger。我也不确定这是否是一种非常干净的方法。

您对此有何看法?

【问题讨论】:

    标签: java jpa domain-driven-design separation-of-concerns


    【解决方案1】:

    我认为您对自己在域中的持久性了解得越少越好。因此,根据将持久性视为域模型的服务而不是将其视为模型的一部分的想法,我建议以下解决方案:

    • 域必须始终处于一致状态;
    • 所以;在不知道未来模型经过验证的情况下,进入模型的更改(来自服务、用户界面)无法更改模型。
    • 含义:当前模型始终一致。

    在一个公式中:未来模型 = CurrentModel.PerformChanges().Validated();

    如何做到这一点?可能使用工作单元类型的构造。 (http://martinfowler.com/eaaCatalog/unitOfWork.html) 每当域对象被更改并被验证时,它都会引发一个它被更改的事件。工作单元管理器负责获取这些事件,然后确保将这些东西放入数据库。当更改无法验证时,不会引发事件并且模型被标记为“无效”。因为您在请求隔离模式下工作,所以这不是问题。当您在共享域模型中工作时,必须在您的域中回滚更改!

    这可能是解决方案中最具学术性的方法,但也许它有助于开始讨论,在这些情况下该怎么做......

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2013-04-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-08-17
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多