使用ORM很好地使用托管实体/代理

时间:2016-06-14 11:47:26

标签: spring hibernate jpa orm proxy-classes

我正在考虑如何处理我的域对象以及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的好处。

问题是:

  1. 这个新设计对这个想法是个好主意吗?
  2. 我是否错过了如何妥善处理这件事?
  3. 注意:尽管我在谈论性能,但我关心的还是关注那些与我合作的ORM和Java不熟悉的开发人员的关注点,可维护性以及更容易使用的问题。

1 个答案:

答案 0 :(得分:0)

感谢@JBNizet,我更清楚地看到了一些事情:

  • 我应该使用merge()方法返回的值。
  • 管理实体并不总是代理。
  • 我不必抽象使用托管实体的事实,这将导致复杂而无效的代码
  • 我选择JPA我不会切换它是真的,除非重写整个模型以代表基于非关系数据库的东西。

所以我只是从原始代码更改我的更新方法,我将保留其余的。