CDI实体管理器注入与EJB容器中的@PersistenceContext实体管理器有何区别?

4
当我们在JAVA EE环境中使用@PersistenceContext注释来注入EntityManager时,容器将创建entityManagerFactory(我猜是为整个会话创建一个),并且通过代理为每个请求创建一个新的EntityManager。
但是,在没有JAVA EE容器的情况下使用CDI,我看到了类似于这样的东西:
public class EntityManagerProducer {
private static EntityManagerFactory emf = Persistence.createEntityManagerFactory("livraria");

    @Produces  
    public EntityManager getEntityManager() {
        return emf.createEntityManager();
    }

    public void close(EntityManager em) {
    em.close();
}

使用这种方法与CDI一起使用,是否会产生相同的效果和性能? 感谢您的帮助。


“将会产生相同的效果和性能”与哪个环境进行比较?这个问题太模糊了,无法回答。 - BalusC
@BalusC 我关注的是 em 范围,这两种注入方法的行为完全相同吗? - Gab
这也取决于环境。EE和SE绝对不同,因为EE通常也暗示了交易上下文。这不能在一句话中完全解释清楚。因此,当前形式的“性能”问题也非常令人困惑和模糊不清。你到底想比较什么是A,什么是B?现在的模糊不确定性甚至超出了A和B本身。 - BalusC
@BalusC 对不起,我之前在问一个问题时发现它是重复的,但实际上并不是。我的兴趣在于EE上下文。如果您参考https://dev59.com/XmQn5IYBdhLWcg3w1qAc#16534957的第一个示例,当使用生产者方法时,容器是否仍能推断出事务上下文。感谢您的时间。 - Gab
@BalusC 如果您能够用一个可接受的答案回答OP的问题并回答我的问题,我将很高兴向您授予奖励。 - Gab
2个回答

3
不,效果不同。像Gab在之前的答案中说的那样,默认情况下@PersistenceContext 为每个事务注入单独的实体管理器。还有一种选择是使用EXTENDED持久化上下文,但这超出了您的问题范围。
使用CDI提供的代码,您会得到每个注入点的一个实例,这与创建每个事务的注入bean不同(很可能不是这样)。
然而,你可以使用RequestScoped生产者来为你的实体管理器服务,就像这样:
 public class EntityManagerProducer {
     private static EntityManagerFactory emf = Persistence.createEntityManagerFactory("livraria");

     @Produces
     @RequestScoped
     public EntityManager getEntityManager() {
         return emf.createEntityManager();
     }
 }

这将为您的Web应用程序提供类似的语义,但如果计划将EJB和非EJB代码混合使用,则可能会出现一些问题,因为此实体管理器不知道正在进行的交易。关于这个问题的一些内容可以在这里找到。
您还应该查看类似的问题,其中您可以找到很多有关此问题的优秀讨论。

2

"使用CDI会产生相同的效果吗?"

不会,使用@PersistenceContext注解,Java EE容器将为每个事务提供一个不同的entityManager实例。

在这里,您将在每个注入点检索唯一的实例,这可能会带来问题(em不是线程安全的,此外,如果在加载相关实体之后在其他地方更新数据,则持久性上下文状态将与数据库状态不一致)。

"最初的回答"


我还想补充一点,你可以通过CDI进行一些额外的编码来注入一个RequestScoped实体管理器。这在这个SO主题中已经讨论过了:https://dev59.com/s2Ik5IYBdhLWcg3wRMNR - Nestor Sokil
好的,那正是我的问题。非常感谢。@NestorSokil 如果您不介意,尝试用简短的回答来涵盖我的和 OP 的关注点,您将获得赏金。 - Gab

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接