我想要的是在 JPA/Hibernate 应用程序中实现存储库模式。我有一个描述我的存储库基本契约的通用接口(interface):
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();
}
下面是这样一个接口(interface)的实现:
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()
时,我收到一个异常,指出没有 Activity 事务。由于我使用的是 JTA 持久性单元,因此通过调用 entityManager.getTransaction()
以编程方式打开事务是非法的。
考虑到这一点,如何修复代码?
最佳答案
首先,您似乎误解了 EntityManager.flush
方法的用途。它不提交由持久性上下文管理的任何更改,只是将 SQL 指令发送到数据库。我的意思是,对于同一个 JTA 事务,当您检索和修改某些实体实例时,更改/SQL 指令被缓存起来等待发送到数据库。如果提交了底层事务,则此更改将与提交指令一起刷新到数据库。如果您在提交事务之前调用 flush
,则仅在调用点之前刷新更改(好吧,一些 SQL 指令可能由于这件事的原因而先前已被刷新),但不会发送提交指令。
如何修复?
我建议你不要混Repository Pattern与交易操纵。
看起来您正在使用容器管理事务 (javaee tutorial),所以只需删除 save
方法并让容器管理事务。这将改变您的关注点,您现在必须关心回滚事务 (throwing exception or invoking setRollbackOnly
),但您不需要显式提交。
关于java - 如何使用 JPA/Hibernate 在 Repository 中实现保存,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31791397/