【发布时间】:2016-06-14 11:47:26
【问题描述】:
我目前正在考虑如何处理我的域对象以及 hibernate 考虑以下几点:
- 我的模型对象直接用JPA注解,没有实体层。
- 在某些数据库繁重的操作中,我不介意调整我的代码,因此我可以充分利用代理,即使我们可以将其视为抽象/实现掩码的泄漏。当然我更喜欢当我可以做其他事情的时候。
- 因为我没有实体层,我没有 DAO 层,实体管理器被认为是 DAO 层(相关:I found JPA, or alike, don't encourage DAO pattern)
但是,我正在考虑改进我正在做的事情,以降低一点复杂性,或者至少将复杂性重新定位到更适合的地方,例如实体的相关服务。也许更抽象的事实是我正在使用 ORM。
这是一个通用的 CRUD 服务,我的所有业务服务都从该服务继承。这段代码是为了向你展示当前的事情是如何完成的(为了清楚起见,注释、日志删除):
public void create(T entity) {
this.entityManager.persist(entity);
}
@Transactional(value = TxType.REQUIRED, rollbackOn=NumeroVersionException.class)
public void update(T entity) throws NumeroVersionException{
try{
this.entityManager.merge(entity);
}catch(OptimisticLockException ole){
throw new NumeroVersionException("for entity "+entity, ole);
}
}
public T read(int id) {
return this.entityManager.find(entityClass, id);
}
public void delete(int id) {
T entity = this.entityManager.getReference(entityClass, id);
this.entityManager.remove(entity);
// edit : removed null test thanks to @JBNizet
}
这种实现的问题在于,如果我想创建一个对象,然后利用代理的优势,我基本上必须创建它然后重新获取它。当然,查询可能不会访问数据库,而只会访问 hibernat 的缓存(虽然不确定)。但这意味着我仍然必须不要忘记重新获取代理。
这意味着我泄露了我在幕后使用 ORM 和代理的事实。
所以我正在考虑将我的界面更改为:
public T read(int id);
public T update(T t)throws NumeroVersionException;
public T create(T object);
public void delete(int id);
List<T> list();
意味着一旦我将一个对象传递给这一层,我将不得不使用返回的值。 并具体实现更新,例如:
public T update(T t){
if(!(t instanceof [Proxy class goes there])){
//+ check if it is a detached proxy
entityManager.merge(t);
}
}
由于每次调用合并都会命中数据库,对于一些只涉及大约 10 个实体的操作,这可能很烦人,我不会在带有代理的更新方法中调用它。
当然,我希望有一些边缘情况,我需要 entityManager 来刷新等等。但我认为这将显着降低我当前代码的复杂性并更好地隔离问题。
简而言之,我试图在服务中重新定位 ORM 代码,这样我就可以隐藏我正在使用 ORM 和代理的事实,并像使用任何其他实现一样使用接口,而不会失去以下好处使用 ORM。
问题是这样的:
- 这个新设计对这个想法来说是个好主意吗?
- 我是否错过了有关如何正确处理此问题的任何信息?
注意:尽管我在谈论性能,但我也关心关注点的隔离、可维护性以及对于不熟悉我所使用的 ORM 和 Java 的开发人员来说更容易使用。
【问题讨论】:
-
我很难理解你在问什么。您说您没有 DAO,但您展示的服务是 DAO:根本没有业务逻辑,纯粹是与持久性相关的操作。 merge() 有充分的理由返回一个实体,并且由于您的 update() 方法直接调用了 merge(),因此它当然应该返回该实体。关于代理,我不知道你关心的是什么。您不必关心是否从 Hibernate 获得代理,以及 update() 是否收到代理。
-
顺便说一句,update()/merge() 几乎从不需要。通常,您从 find() 或查询中获取托管实体,对其进行修改,仅此而已。 JPA 使更改自动持久化。
-
@JBNizet 我有比这更多的方法,这个类是一个泛型,可以处理我真正的服务层继承的 crud 操作。一些覆盖它以添加业务逻辑,然后依赖 super.create/update 来处理实体部分
-
@JBNizet 实际上我的问题是:在比服务更高的级别上,我应该像使用 ORM 代理一样使用我的对象(将自动更新并启动)还是应该将它们用作我的服务实现可能不是 ORM 吗?
-
@JBNizet :我编辑了我的帖子,试图让我的问题更容易理解。我也考虑了 getReference() 点
标签: spring hibernate jpa orm proxy-classes