Java 注入 EntityManager Vs。实体管理器工厂

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/1310087/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-12 08:05:05  来源:igfitidea点击:

Injecting EntityManager Vs. EntityManagerFactory

javaspringjpaentitymanager

提问by SB.

A long question, please bear with me.

一个很长的问题,请耐心等待。

We are using Spring+JPA for a web application. My team is debating over injecting EntityManagerFactoryin the GenericDAO(a DAO based on Generics something on the lines provided by APPFUSE, we do not use JpaDaosupportfor some reason) over injecting an EntityManager. We are using "application managed persistence".

我们正在将 Spring+JPA 用于 Web 应用程序。我的团队在讨论如何在注入EntityManagerFactoryGenericDAO(基于泛型的东西对AppFuse中提供的线DAO,我们不使用JpaDaosupport过的注射某种原因)EntityManager。我们正在使用“应用程序管理的持久性”。

The arguments against injecting a EntityManagerFactoryis that its too heavy and so is not required, the EntityManagerdoes what we need. Also, as Spring would create a new instance of a DAO for every web request(I doubt this) there are not going to be any concurrency issues as in the same EntityManagerinstance is shared by two threads.

反对注入 a 的论点EntityManagerFactory是它太重了,所以不是必需的,EntityManager它做我们需要的。此外,由于 Spring 会为每个 Web 请求创建一个新的 DAO 实例(我对此表示怀疑),因此不会出现任何并发问题,因为同一EntityManager实例由两个线程共享。

The argument for injecting EFM is that its a good practice over all its always good to have a handle to a factory.

注入 EFM 的论点是,拥有工厂的句柄始终是一种很好的做法。

I am not sure which is the best approach, can someone please enlighten me?

我不确定哪种方法是最好的,有人可以启发我吗?

采纳答案by skaffman

The pros and cons of injecting EntityManagerFactory vs EntityManager are all spelled out in the Spring docs here, I'm not sure if I can improve on that.

优点和注入的EntityManagerFactory VS的EntityManager的利弊都在Spring文档阐述了这里,我不知道如果我能在改善。

Saying that, there are some points in your question that should be cleared up.

这么说吧,你的问题有几点需要澄清。

...Spring would create a new instance of a DAO for every web request...

...Spring 将为每个 Web 请求创建一个新的 DAO 实例...

This is not correct. If your DAO is a Spring bean, then it's a singleton, unless you configure it otherwise via the scopeattribute in the bean definition. Instantiating a DAO for every request would be crazy.

这是不正确的。如果你的 DAO 是一个 Spring bean,那么它就是一个单例,除非你通过scopebean 定义中的属性另外配置它。为每个请求实例化一个 DAO 会很疯狂。

The argument for injecting EMF is that its a good practice over all its always good to have a handle to a factory.

注入 EMF 的论点是,拥有工厂的句柄始终是一种很好的做法。

This argument doesn't really hold water. General good practice says that an object should be injected with the minimum collaborators it needs to do its job.

这个论点并没有真正站得住脚。一般的良好做法是,应该向对象注入完成其工作所需的最少协作者。

回答by Ga?l Marziou

I found that setting the @Repository Spring annotation on our DAOs and having EntityManager managed by Spring and injected by @PersistenceContext annotation is the most convenient way to get everything working fluently. You benefit from the thread safety of the shared EntityManager and exception translation. By default, the shared EntityManager will manage transactions if you combine several DAOs from a manager for instance. In the end you'll find that your DAOs will become anemic.

我发现在我们的 DAO 上设置 @Repository Spring 注释并让 EntityManager 由 Spring 管理并由 @PersistenceContext 注释注入是让一切顺利工作的最方便的方法。您受益于共享 EntityManager 和异常转换的线程安全性。默认情况下,共享 EntityManager 将管理事务,例如,如果您组合来自一个管理器的多个 DAO。最后你会发现你的 DAO 会变得贫乏。

回答by SB.

I am putting down what I have finally gathered. From the section "Implementing DAOs based on plain JPA" in the Spring Reference:

我正在放下我最终收集到的东西。从Spring 参考中的“基于普通 JPA 实现 DAO”部分:

Although EntityManagerFactory instances are thread-safe, EntityManager instances are not. The injected JPA EntityManager behaves like an EntityManager fetched from an application server's JNDI environment, as defined by the JPA specification. It delegates all calls to the current transactional EntityManager, if any; otherwise, it falls back to a newly created EntityManager per operation, in effect making its usage thread-safe.

尽管 EntityManagerFactory 实例是线程安全的,但 EntityManager 实例不是。注入的 JPA EntityManager 的行为类似于从应用程序服务器的 JNDI 环境中获取的 EntityManager,如 JPA 规范所定义的。它将所有调用委托给当前事务 EntityManager,如果有的话;否则,它会回退到每个操作新创建的 EntityManager,实际上使其使用线程安全。

This means as per JPA specifications EntityManager instances are not thread safe, but if Spring handles them, they are made thread safe.

这意味着根据 JPA 规范 EntityManager 实例不是线程安全的,但如果 Spring 处理它们,它们将成为线程安全的。

If you are using Spring, it is better to inject EntityManagers instead of EntityManagerFactory.

如果您使用的是 Spring,最好注入 EntityManagers 而不是 EntityManagerFactory。

回答by James McMahon

I think this has already been well covered, but just to reinforce a few points.

我认为这已经很好地涵盖了,但只是为了强调几点。

  • The DAO, if injected by Spring, is a singleton by default. You have to explicitly set the scope to prototype to create a new instance every time.

  • The entity manger injected by @PersistenceContext is thread safe.

  • 如果由 Spring 注入,DAO默认为单例。您必须明确地将范围设置为原型,以便每次都创建一个新实例。

  • @PersistenceContext 注入的实体管理器是线程安全的

That being said, I did have some issues on with a singleton DAO in my multi-threaded application. I ended up making the DAO a instanced bean and that solved the problem.So while the documentation may say one thing, you probably want to test your application thoroughly.

话虽如此,在我的多线程应用程序中,我确实遇到了一些关于单例 DAO 的问题。我最终使 DAO 成为一个实例化的 bean 并解决了这个问题。因此,虽然文档可能会说明一件事,但您可能希望彻底测试您的应用程序。

Follow-up:

跟进:

I think part of my problem is I am using

我认为我的部分问题是我正在使用

@PersistenceContext(unitName = "unit",
    type = PersistenceContextType.EXTENDED)

If you use PersistenceContextType.EXTENDED, keep in mind you have to, if I understand correctly, manually close the transaction. See thisthread for more information.

如果您使用 PersistenceContextType.EXTENDED,请记住,如果我理解正确,您必须手动关闭事务。有关更多信息,请参阅线程。

Another Follow-up:

另一个后续:

Using an instanced DAO is an extremely bad idea. Each instance of the DAO will have its own persistence cache and changes to one cache will not be recognized by other DAO beans. Sorry for the bad advice.

使用实例化 DAO 是一个非常糟糕的主意。DAO 的每个实例都有自己的持久性缓存,其他 DAO bean 将无法识别对一个缓存的更改。抱歉给了不好的建议。