问题描述
我有一个尝试设置JPA的应用程序上下文:
I have an application context where I am trying to setup JPA:
application-context.xml :
<bean class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor">
<property name="persistenceUnits">
<map>
<entry key="pu1" value="pu1" />
<entry key="pu2" value="pu2" />
</map>
</property>
<property name="defaultPersistenceUnitName" value="pu1" />
</bean>
<bean id="emf1" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
<property name="showSql" value="true" />
<property name="generateDdl" value="false" />
<property name="databasePlatform" value="org.hibernate.dialect.MySQLDialect" />
</bean>
</property>
<property name="persistenceUnitName" value="pu1" />
<property name="dataSource" ref="dataSource1" />
</bean>
<bean id="emf2" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
<property name="showSql" value="true" />
<property name="generateDdl" value="false" />
<property name="databasePlatform" value="org.hibernate.dialect.SQLServer2005Dialect" />
</bean>
</property>
<property name="persistenceUnitName" value="pu2" />
<property name="dataSource" ref="dataSource2" />
</bean>
<!-- Enable annotation style of managing transactions -->
<tx:annotation-driven />
<bean id="transactionManager1" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="emf1" />
<property name="dataSource" ref="dataSource1" />
</bean>
<bean id="transactionManager2" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="emf2" />
<property name="dataSource" ref="dataSource2" />
</bean>
<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="locations">
<list>
<value>classpath:config/db/database.properties</value>
</list>
</property>
<property name="ignoreUnresolvablePlaceholders" value="true" />
<property name="ignoreResourceNotFound" value="true" />
<property name="systemPropertiesModeName" value="SYSTEM_PROPERTIES_MODE_OVERRIDE"/>
</bean>
<!-- The actual config of the database is read from the properties file database.properties -->
<bean id="dataSource1" class="com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method="close"
p:acquireIncrement="5" p:idleConnectionTestPeriod="14400" p:maxPoolSize="50" p:maxStatements="15"
p:minPoolSize="5" p:testConnectionOnCheckout="true" p:preferredTestQuery="SELECT 4;"
p:driverClass="${db.system1.driver}" p:jdbcUrl="${db.system1.url}" p:user="${db.system1.user}" p:password="${db.system1.password}" />
<bean id="dataSource2" class="com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method="close" p:acquireIncrement="5" p:idleConnectionTestPeriod="60" p:maxPoolSize="10"
p:maxStatements="50" p:minPoolSize="3" p:testConnectionOnCheckout="true" p:preferredTestQuery="SELECT 4;"
p:driverClass="${db.system2.driver}" p:jdbcUrl="${db.system2.url}" p:user="${db.system2.user}" p:password="${db.system2.password}" />
<context:annotation-config />
<context:component-scan base-package="com.myapp.model.manager"/>
persistence.xml :
<persistence-unit name="pu1" transaction-type="RESOURCE_LOCAL">
<provider>org.hibernate.ejb.HibernatePersistence</provider>
<class>com.myapp.model.Address</class>
<class>com.myapp.model.AgressoFile</class>
<class>com.myapp.model.CustomerGroup</class>
...
</persistence-unit>
<persistence-unit name="pu2" transaction-type="RESOURCE_LOCAL">
<provider>org.hibernate.ejb.HibernatePersistence</provider>
<class>com.myapp.model.CompetenceArea</class>
<class>com.myapp.model.CompetenceAreaCategory</class>
...
</persistence-unit>
我正在通过以下方式在 web.xml 中加载应用程序上下文:
I am loading application context in a web.xml this way:
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>
/WEB-INF/spring/application-context.xml
</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
位于扫描包"com.myapp.model.manager"中的
CompetenceAreaManager 类具有以下内容:
CompetenceAreaManager class that locates in the scanned package "com.myapp.model.manager" has the following content:
@Service
public class CompetenceAreaManager {
@PersistenceUnit(unitName = "pu2")
private EntityManagerFactory entityManagerFactory;
@SuppressWarnings("unchecked")
public List<CompetenceArea> getCompetenceAreas() {
List<CompetenceArea> competenceAreaList = null;
EntityManager em = entityManagerFactory.createEntityManager();
Query q = em.createNamedQuery(CompetenceArea.FIND_ALL);
competenceAreaList = q.getResultList();
return competenceAreaList;
}
public void setEntityManagerFactory(EntityManagerFactory entityManagerFactory) {
this.entityManagerFactory = entityManagerFactory;
}
}
但是,当我尝试在Tomcat 7.0中运行该应用程序时,出现以下错误:
However, when I try to run the application in Tomcat 7.0, I get the following error:
SEVERE: Exception sending context initialized event to listener instance of class org.springframework.web.context.ContextLoaderListener
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'competenceAreaManager': Injection of persistence dependencies failed; nested exception is java.lang.IllegalStateException: Could not obtain EntityManagerFactory [pu2] from JNDI
at org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor.postProcessPropertyValues(PersistenceAnnotationBeanPostProcessor.java:343)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1122)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:522)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:461)
at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:295)
...
Caused by: java.lang.IllegalStateException: Could not obtain EntityManagerFactory [pu2] from JNDI
at org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor.getPersistenceUnit(PersistenceAnnotationBeanPostProcessor.java:435)
at org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor$PersistenceElement.resolveEntityManagerFactory(PersistenceAnnotationBeanPostProcessor.java:643)
at org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor$PersistenceElement.getResourceToInject(PersistenceAnnotationBeanPostProcessor.java:637)
at org.springframework.beans.factory.annotation.InjectionMetadata$InjectedElement.inject(InjectionMetadata.java:150)
at org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:87)
...
Caused by: javax.naming.NameNotFoundException: Name [pu2] is not bound in this Context. Unable to find [pu2].
at org.apache.naming.NamingContext.lookup(NamingContext.java:820)
at org.apache.naming.NamingContext.lookup(NamingContext.java:168)
at org.apache.naming.SelectorContext.lookup(SelectorContext.java:158)
at javax.naming.InitialContext.lookup(Unknown Source)
at org.springframework.jndi.JndiTemplate$1.doInContext(JndiTemplate.java:154)
...
知道我在做什么错吗?
推荐答案
如果使用persistenceUnits配置PersistenceAnnotationBeanPostProcessor,则将向PersistenceAnnotationBeanPostProcessor通知PU来自JNDI(如setPersistenceUnits()方法的javadoc所述).堆栈跟踪实际上显示了失败的JNDI查找.
If you configure the PersistenceAnnotationBeanPostProcessor with persistenceUnits, you are informing the PersistenceAnnotationBeanPostProcessor that PUs come from JNDI (as the javadoc for setPersistenceUnits() methods mentions it). The stack trace actually shows the failing JNDI lookup.
由于您在application-context.xml中使用<context:annotation-config/>
,因此无需声明PersistenceAnnotationBeanPostProcessor,因为它将被自动注册,通过读取位于您的META-INF/persistence.xml文件来查找PU.在类路径中,这实际上是您期望的.
Since you are using <context:annotation-config/>
in application-context.xml, you don't need to declare a PersistenceAnnotationBeanPostProcessor, because one will be automatically registered, which looks up PUs by reading your META-INF/persistence.xml files located in the classpath, which is actually what you expect.
您的配置应该像这样简单:
Your configuration should be as simple as this :
persistence.xml 保持不变
CompetenceAreaManager
就像谢尔盖·马卡罗夫(Sergey Makarov)提到的那样,只需使用@PersistenceContext注入EntityManager而不是使用@PersistenceUnit注入EntityManagerFactory. em是事务性的(因此绑定到线程,从而确保DAO的线程安全),并且您仍然可以使用unitName配置@PersistenceContext以便指定EM必须绑定到的PU.
As Sergey Makarov mentions it, just inject EntityManager with @PersistenceContext instead of injecting EntityManagerFactory with @PersistenceUnit. The em is transactional (thus bound to the thread, thus ensuring thread-safety for your DAO), and you can still configure @PersistenceContext with unitName in order to specify the PU the EM has to be bound to.
application-context.xml
只需删除PersistenceAnnotationBeanPostProcessor bean的声明.文件的其余部分保持不变.
Just drop the declaration of the PersistenceAnnotationBeanPostProcessor bean. The rest of the file remains unchanged.
我还没有尝试过您的特定配置(2个PU),但是我提到的配置是我一直使用的成功配置.
I haven't tried your particular config (2 PUs), but the configuration I mention is the one I have always been using, with success.
这篇关于Spring,JPA,Hibernate,Tomcat:加载Spring应用程序上下文时找不到持久性单元的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!