在 Spring 个数据存储库之上使用 EntityManager

Using EntityManager on top of Spring Data Repositories

最近,我遇到了以下代码:

@Transactional
public MyEntity insert(MyEntity entity) {
    MyEntity merged = entityManager.merge(entity);
    return myEntityRepository.save(merged);
}

其中实体管理器定义如下:

@PersistenceContext private EntityManager entityManager;

存储库是 Spring QueryDSL 存储库:

@Repository
public interface MyEntityRepository extends QueryDslRepository<MyEntity>{
}

我的问题是,当我们使用 myEntityRepository 持久化实体时,是否真的有必要调用 entityManager.merge(entity)?是否有 entityManager 正在做的存储库不能做的事情?调用存储库还不够吗?

在我看来,这就像货物崇拜编程。 implementation of save() 已经在必要时进行了合并(有时在不需要时):

/*
 * (non-Javadoc)
 * @see org.springframework.data.repository.CrudRepository#save(java.lang.Object)
 */
@Transactional
public <S extends T> S save(S entity) {

    if (entityInformation.isNew(entity)) {
        em.persist(entity);
        return entity;
    } else {
        return em.merge(entity);
    }
}

对我来说,这看起来是一个非常危险的代码,其意图有点模糊并且有些过度设计:

  1. 你能 100% 保证在你的层和存储库之间共享同一个事务管理器吗?否则你就有麻烦了。
  2. 你只是在做双重工作(@Jens 的回答表明了这一点)。
  3. @Transactional 这里只会让事情变得更糟(如果你有一些非标准的刷新策略)。特别要注意,如果您从与通过代理工作的相同 class 中调用方法,它将无法工作。
  4. 如果你真的打算insert()(新记录)你为什么需要merge()

我的投票是——按照@Jens 指出的那样使用save()。如果您确实需要 insert() 功能,那么您可能需要具有更新保护的真实事务,在这种情况下,我会在存储库层上做一些自定义代码。希望你不需要它。