简体   繁体   English

注入EntityManager Vs. EntityManagerFactory的

[英]Injecting EntityManager Vs. EntityManagerFactory

A long question, please bear with me. 一个很长的问题,请耐心等待。

We are using Spring+JPA for a web application. 我们将Spring + JPA用于Web应用程序。 My team is debating over injecting EntityManagerFactory in the GenericDAO (a DAO based on Generics something on the lines provided by APPFUSE, we do not use JpaDaosupport for some reason) over injecting an EntityManager . 我的团队正在讨论在GenericDAO注入EntityManagerFactory (在APPFUSE提供的基于泛型的DAO,我们不会出于某种原因使用JpaDaosupport )而不是注入EntityManager We are using "application managed persistence". 我们正在使用“应用程序管理持久性”。

The arguments against injecting a EntityManagerFactory is that its too heavy and so is not required, the EntityManager does what we need. 反对注入EntityManagerFactory的论点是它太重而且不需要, EntityManager做我们需要的。 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 EntityManager instance is shared by two threads. 此外,由于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? 我不确定哪种方法最好,有人可以赐教吗?

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 scope attribute in the bean definition. 如果您的DAO是一个Spring bean,那么它是一个单例,除非您通过bean定义中的scope属性进行配置。 Instantiating a DAO for every request would be crazy. 为每个请求实例化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. 一般的良好实践表明,应该向一个对象注入完成其工作所需的最少合作者。

I am putting down what I have finally gathered. 我正在放下我最终收集到的东西。 From the section " Implementing DAOs based on plain JPA " in the Spring Reference: 从Spring Reference中的“ 基于普通JPA实现DAO ”一节:

Although EntityManagerFactory instances are thread-safe, EntityManager instances are not. 虽然EntityManagerFactory实例是线程安全的,但EntityManager实例不是。 The injected JPA EntityManager behaves like an EntityManager fetched from an application server's JNDI environment, as defined by the JPA specification. 注入的JPA EntityManager的行为类似于从应用程序服务器的JNDI环境获取的EntityManager,如JPA规范所定义。 It delegates all calls to the current transactional EntityManager, if any; 它将所有调用委托给当前的事务性EntityManager,如果有的话; otherwise, it falls back to a newly created EntityManager per operation, in effect making its usage thread-safe. 否则,它会回退到每个操作新创建的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。

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 . 如果由Spring注入,DAO 默认为单例 You have to explicitly set the scope to prototype to create a new instance every time. 您必须将范围显式设置为prototype,以便每次都创建一个新实例。

  • The entity manger injected by @PersistenceContext is thread safe . 由@PersistenceContext注入的实体管理器是线程安全的

That being said, I did have some issues on with a singleton DAO in my multi-threaded application. 话虽这么说,我的多线程应用程序中的单例DAO确实存在一些问题。 I ended up making the DAO a instanced bean and that solved the problem. 我最终使DAO成为一个实例bean,并解决了这个问题。 So while the documentation may say one thing, you probably want to test your application thoroughly. 因此,虽然文档可能会说一件事,但您可能希望彻底测试您的应用程序。

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. 如果您使用PersistenceContextType.EXTENDED,请记住,如果我理解正确,您必须手动关闭事务。 See this thread for more information. 有关更多信息,请参阅主题。

Another Follow-up: 另一个后续行动:

Using an instanced DAO is an extremely bad idea. 使用实例化DAO是一个非常糟糕的主意。 Each instance of the DAO will have its own persistence cache and changes to one cache will not be recognized by other DAO beans. DAO的每个实例都有自己的持久性缓存,其他DAO bean无法识别对一个缓存的更改。 Sorry for the bad advice. 抱歉,不好的建议。

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. 我发现在我们的DAO上设置@Repository Spring注释并使用Spring管理的EntityManager并通过@PersistenceContext注释注入是使一切工作流畅的最方便的方法。 You benefit from the thread safety of the shared EntityManager and exception translation. 您可以从共享EntityManager的线程安全性和异常转换中受益。 By default, the shared EntityManager will manage transactions if you combine several DAOs from a manager for instance. 默认情况下,如果您将来自管理器的多个DAO组合在一起,则共享的EntityManager将管理事务。 In the end you'll find that your DAOs will become anemic. 最后你会发现你的DAO会变得贫血。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM