如何使用JPA / Hibernate在存储库中实现保存

时间:2015-08-03 15:38:54

标签: java hibernate jpa ddd-repositories

我想要的是在JPA / Hibernate应用程序中实现Repository模式。我有一个通用接口,描述了我的存储库的基本合同:

public interface EntityRepository<Entity extends Object, EntityId> {
    Entity add(Entity entity);

    Entity byId(EntityId id);

    void remove(Entity entity);

    void removeById(EntityId id);

    void save();

    List<Entity> toList();
}

以下是这种界面的实现:

public class EntityRepositoryHibernate<Entity extends Object, EntityId>
       implements Serializable,
                  EntityRepository<Entity, EntityId> {
    private static final long serialVersionUID = 1L;

    @Inject
    protected EntityManager entityManager;
    protected Class<Entity> entityClass;

    public EntityRepositoryHibernate(Class<Entity> entityClass) {
        this.entityClass = entityClass;
    }

    public EntityManager getEntityManager() {
        return entityManager;
    }

    @Override
    public Entity add(Entity entity) {
        entityManager.persist(entity);
        return entity;
    }

    @SuppressWarnings("unchecked")
    @Override
    public Entity byId(EntityId id) {
        DetachedCriteria criteria = criteriaDAO.createDetachedCriteria(entityClass);
        criteria.add(Restrictions.eq("id", id));
        return (Entity)criteriaDAO.executeCriteriaUniqueResult(criteria);
    }

    @Override
    public void remove(Entity entity) {
        if(entity==null)
            return;
        entityManager.remove(entity);
    }

    @Override
    public void removeById(EntityId id) {
        remove(byId(id));
    }

    @Override
    public List<Entity> toList() {
        throw new UnsupportedOperationException("toList() not implemented in "+entityClass.getName()); 
    }

    @Override
    public void save() {
        entityManager.flush();
    }
}

save()外,所有方法都运行正常,因此这是重点。

据我了解,Hibernate能够跟踪查询返回的任何实例中的所有更改(byId()方法)。所以,save()方法的想法是保存任何检索和更改的实例,这就是为什么方法不接收任何参数,它应该保存所有必须保存的东西(这意味着,任何持久性)在存储库存活时已经重新启动并以某种方式更新的实例。

在可能的情况下,我可以调用byId() 10次来检索10个不同的实例,只更改其中的4个。我们的想法是,通过调用save()一次,这4个实例将保存在数据服务器中。

问题是当我呼叫flush()时,我收到一条例外,说明没有活动的交易。由于我使用的是JTA持久性单元,因此通过调用entityManager.getTransaction()以编程方式打开转换是违法的。

考虑到,如何修复代码?

1 个答案:

答案 0 :(得分:1)

首先,您似乎错过了EntityManager.flush方法的目的。它不提交由持久性上下文管理的任何更改,只是将SQL指令发送到数据库。我的意思是,对于相同的JTA事务,当您检索和修改某些实体实例时,更改/ SQL指令将被缓存,等待发送到数据库。如果提交了基础事务,则此更改将与提交指令一起刷新到数据库。如果在提交事务之前调用flush,则只刷新更改,直到调用点(以及某些SQL指令之前可能因为此问题而被刷新),但不会发送提交指令。

如何解决?

我建议你不要将Repository Pattern与交易操作混合起来。

看起来您正在使用容器管理事务(javaee tutorial),因此只需擦除save方法并让容器管理事务。这将改变您的注意力,您现在必须关注回滚交易(throwing exception or invoking setRollbackOnly),但您不需要明确提交。