我想要的是在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()
以编程方式打开转换是违法的。
考虑到,如何修复代码?
答案 0 :(得分:1)
首先,您似乎错过了EntityManager.flush
方法的目的。它不提交由持久性上下文管理的任何更改,只是将SQL指令发送到数据库。我的意思是,对于相同的JTA事务,当您检索和修改某些实体实例时,更改/ SQL指令将被缓存,等待发送到数据库。如果提交了基础事务,则此更改将与提交指令一起刷新到数据库。如果在提交事务之前调用flush
,则只刷新更改,直到调用点(以及某些SQL指令之前可能因为此问题而被刷新),但不会发送提交指令。
如何解决?
我建议你不要将Repository Pattern与交易操作混合起来。
看起来您正在使用容器管理事务(javaee tutorial),因此只需擦除save
方法并让容器管理事务。这将改变您的注意力,您现在必须关注回滚交易(throwing exception or invoking setRollbackOnly
),但您不需要明确提交。