java - 如何使用 JPA/Hibernate 在 Repository 中实现保存

标签 java hibernate jpa ddd-repositories

我想要的是在 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/

相关文章:

java - HIbernate映射异常: PropertyNotFoundException: Could not find a setter

java - 如何在hibernate中使用命名查询访问子表字段

java - 带有空参数的 Spring 数据 jpa native 查询(PostgreSQL)

java - 方法内可变数组长度

spring - @ManyToOne 的 "optional"参数是否使用 Kotlin 的可为空性自动设置

java - 如何通过引用键相关的其他表字段查找(使用JPA)?

java - Spring存储库: @CacheEvict on save methods

java - 我的表在使用修改和查询注释时没有映射?

java - 尝试在 Linux 上的 Websphere Real Time JVM 上运行实时 Java 代码时出现 UnsatisfiedLinkError

Java 应用程序运行速度比应有的慢