【发布时间】: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