Spring 3.1 + Hibernate 4.1 JPA,实体管理器工厂注册两次

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/10866263/
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-09-08 05:09:08  来源:igfitidea点击:

Spring 3.1 + Hibernate 4.1 JPA, Entity manager factory is registered twice

springhibernatejpahibernate-entitymanager

提问by Wilson Hymanson

I'm using Spring Framework 3.1 with Hibernate 4.1 as a JPA provider, and I have a fully functional setup, but every time the web app is started I see this warning message:

我使用 Spring Framework 3.1 和 Hibernate 4.1 作为 JPA 提供程序,并且我有一个功能齐全的设置,但是每次启动 Web 应用程序时,我都会看到以下警告消息:

14:28:12,725  WARN pool-2-thread-12 internal.EntityManagerFactoryRegistry:80 - HHH000436: Entity manager factory name (something) is already registered.  If entity manager will be clustered or passivated, specify a unique value for property 'hibernate.ejb.entitymanager_factory_name'

The application functions just fine, but warning messages like that bother me, and hours of searching and tweaking and experimenting have lead me nowhere. I've tried changing the factory name and adding and omitting chunks of configuration, all to no avail. It appears that something in Spring or Hibernate is just initializing the entity manager factory twice.

该应用程序运行良好,但像这样的警告消息困扰着我,数小时的搜索、调整和试验使我一无所获。我试过更改工厂名称并添加和省略配置块,但都无济于事。似乎 Spring 或 Hibernate 中的某些东西只是两次初始化实体管理器工厂。

FYI, I'm using the packagesToScan functionality of the LocalContainerEntityManagerFactoryBean to configure the entity manager without a persistence.xml file.

仅供参考,我正在使用 LocalContainerEntityManagerFactoryBean 的 packagesToScan 功能来配置没有 persistence.xml 文件的实体管理器。

I've pared down my spring context XML to the following and the problem persists:

我已将 spring 上下文 XML 缩减为以下内容,但问题仍然存在:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="
           http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
           http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

  <context:property-placeholder location="classpath:jdbc.properties"/>
  <bean id="dataSource" class="org.apache.tomcat.jdbc.pool.DataSource" destroy-method="close">
    <property name="driverClassName" value="${jdbc.nightsword.driverClassName}"/>
    <property name="url" value="${jdbc.nightsword.url}"/>
    <property name="username" value="${jdbc.nightsword.username}"/>
    <property name="password" value="${jdbc.nightsword.password}"/>
  </bean>

  <bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
    <property name="jpaVendorAdapter">
      <bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter"/>
    </property>
    <property name="dataSource" ref="dataSource"/>
    <property name="packagesToScan" value="x.y"/>
  </bean>
</beans>

For completeness, here's hibernate.properties:

为了完整起见,这里是 hibernate.properties:

hibernate.dialect=org.hibernate.dialect.MySQL5Dialect
hibernate.ejb.entitymanager_factory_name=something

And here's excerpted debug-level log output from both org.springframework.orm and org.hibernate. You can see how at 14:40:06,911 the EntityManagerFactory is registered from the first time, and immediately thereafter the LocalContainerEntityManagerFactoryBean appears to start all over from the beginning. Huh.

这里摘录了 org.springframework.orm 和 org.hibernate 的调试级日志输出。您可以看到 14:40:06,911 EntityManagerFactory 是如何从第一次注册开始的,紧接着 LocalContainerEntityManagerFactoryBean 似乎从头开始。呵呵。

INFO: Deploying web application archive /opt/local/share/java/tomcat7/webapps/nightsword.war
14:40:06,149  INFO pool-2-thread-13 jpa.LocalContainerEntityManagerFactoryBean:264 - Building JPA container EntityManagerFactory for persistence unit 'default'
14:40:06,219 DEBUG pool-2-thread-13 type.BasicTypeRegistry:143 - Adding type registration boolean -> org.hibernate.type.BooleanType@4cb91eff

...

14:40:06,882 DEBUG pool-2-thread-13 internal.SessionFactoryRegistry:62 - Initializing SessionFactoryRegistry : org.hibernate.internal.SessionFactoryRegistry@161bb7fe
14:40:06,882 DEBUG pool-2-thread-13 internal.SessionFactoryRegistry:75 - Registering SessionFactory: a3219dd8-7d59-45ac-9a5a-0d13e38dbb04 (<unnamed>)
14:40:06,882 DEBUG pool-2-thread-13 internal.SessionFactoryRegistry:82 - Not binding SessionFactory to JNDI, no JNDI name configured
14:40:06,882 DEBUG pool-2-thread-13 internal.SessionFactoryImpl:487 - Instantiated session factory
14:40:06,882 DEBUG pool-2-thread-13 internal.SessionFactoryImpl:1119 - Checking 0 named HQL queries
14:40:06,883 DEBUG pool-2-thread-13 internal.SessionFactoryImpl:1142 - Checking 0 named SQL queries
14:40:06,887 DEBUG pool-2-thread-13 internal.StatisticsInitiator:110 - Statistics initialized [enabled=false]
14:40:06,910 DEBUG pool-2-thread-13 internal.EntityManagerFactoryRegistry:56 - Initializing EntityManagerFactoryRegistry : org.hibernate.ejb.internal.EntityManagerFactoryRegistry@75cc9008
14:40:06,911 DEBUG pool-2-thread-13 internal.EntityManagerFactoryRegistry:66 - Registering EntityManagerFactory: something 
14:40:06,967  INFO pool-2-thread-13 jpa.LocalContainerEntityManagerFactoryBean:264 - Building JPA container EntityManagerFactory for persistence unit 'default'
14:40:06,967 DEBUG pool-2-thread-13 type.BasicTypeRegistry:143 - Adding type registration boolean -> org.hibernate.type.BooleanType@4cb91eff

...

14:40:07,128 DEBUG pool-2-thread-13 internal.SessionFactoryRegistry:75 - Registering SessionFactory: 81a9b5a6-83aa-46ee-be68-d642e6fda584 (<unnamed>)
14:40:07,128 DEBUG pool-2-thread-13 internal.SessionFactoryRegistry:82 - Not binding SessionFactory to JNDI, no JNDI name configured
14:40:07,129 DEBUG pool-2-thread-13 internal.SessionFactoryImpl:487 - Instantiated session factory
14:40:07,129 DEBUG pool-2-thread-13 internal.SessionFactoryImpl:1119 - Checking 0 named HQL queries
14:40:07,129 DEBUG pool-2-thread-13 internal.SessionFactoryImpl:1142 - Checking 0 named SQL queries
14:40:07,129 DEBUG pool-2-thread-13 internal.StatisticsInitiator:110 - Statistics initialized [enabled=false]
14:40:07,130 DEBUG pool-2-thread-13 internal.EntityManagerFactoryRegistry:66 - Registering EntityManagerFactory: something 
14:40:07,130  WARN pool-2-thread-13 internal.EntityManagerFactoryRegistry:80 - HHH000436: Entity manager factory name (something) is already registered.  If entity manager will be clustered or passivated, specify a unique value for property 'hibernate.ejb.entitymanager_factory_name'

采纳答案by eolith

How are you initializing your Spring Application Context? Are you using Spring MVC?

你如何初始化你的 Spring 应用程序上下文?你在使用 Spring MVC 吗?

I've seen sometimes Spring MVC XML configurations importing the other app. context XML, causing instancing twice some beans because they are declared in the application context and the web application context.

我有时会看到 Spring MVC XML 配置导入其他应用程序。上下文 XML,导致某些 bean 实例化两次,因为它们是在应用程序上下文和 Web 应用程序上下文中声明的。

回答by zagyi

I came across the same issue but in a different scenario. The EntityManagerFactoryRegistryproduces the same HHH000436warning, when executing multiple tests in the same run (i.e. the same JVM) started from my IDE.

我遇到了同样的问题,但在不同的情况下。在从我的 IDE 启动的同一个运行(即同一个 JVM)中执行多个测试时,EntityManagerFactoryRegistry会产生相同的HHH000436警告。

The problem can surface in case there are at least twotest classes using the SpringJUnit4ClassRunnerto load differentSpring test application contexts each containing an EntityManagerFactory.

如果至少有两个测试类使用SpringJUnit4ClassRunner加载不同的Spring 测试应用程序上下文,每个都包含一个EntityManagerFactory.

The root cause is that Hibernate maintains a static registry of EntityManagerFactoryinstances, where the creation of the second instance may cause the collision the log message is about. So why isn't the first instance deregistered after the first test finished executing? It normally would when the app context containing that EntityManagerFactoryinstance gets destroyed. The reason it doesn't happen during test execution is that the Spring test context framework caches all loaded contexts in order to avoid re-loading the exact same context potentially needed by multiple tests. As a result, beans in these contexts doesn't get destroyed until after the last test finished executing, and Hibernate will just collect all the EntityManagerFactoryinstances ever created.

根本原因是 Hibernate 维护了一个静态的EntityManagerFactory实例注册表,其中第二个实例的创建可能会导致日志消息所涉及的冲突。那么为什么在第一个测试完成后第一个实例没有被注销?它通常会在包含该EntityManagerFactory实例的应用程序上下文被销毁时发生。在测试执行期间它不会发生的原因是 Spring 测试上下文框架缓存所有加载的上下文,以避免重新加载多个测试可能需要的完全相同的上下文。因此,在这些上下文中的 bean 直到最后一个测试完成执行后才会被销毁,并且 Hibernate 将只收集EntityManagerFactory曾经创建的所有实例。

It's really a non-issue, but if someone is really annoyed by the warning message, there are a few possible ways to avoid seeing it:

这确实不是问题,但如果有人真的对警告消息感到恼火,有几种可能的方法可以避免看到它:

  1. Make sure the EntityManagerFactoryinstances get a different name (they are keyed by name in the registry). Chek the constructor of EntityManagerFactoryImplon how the name is derived.
  2. Use @DirtiesContexton the test class to cause the SpringJUnit4ClassRunnerto close the context and remove it from its context cache immediately after executing the test class.
  3. Simply set the logging level of EntityManagerFactoryRegistryto error...
  1. 确保EntityManagerFactory实例获得不同的名称(它们在注册表中按名称键入)。EntityManagerFactoryImpl检查名称如何派生的构造函数。
  2. 使用@DirtiesContext的测试类导致SpringJUnit4ClassRunner关闭的背景和执行测试类后,立即从它的上下文高速缓存中删除。
  3. 只需将日志级别设置EntityManagerFactoryRegistry为错误...

Hope this helps someone.

希望这可以帮助某人。