[英]Spring + 2 Hibernate datasources + 2 TransactionManagers: NoSuchBeanDefinitionException
I have a Spring Web application with two Hibernate data sources, and they are being managed with two separate transaction managers. 我有一个带有两个Hibernate数据源的Spring Web应用程序,它们由两个单独的事务管理器管理。 The datasources are completely independent, schema-wise.
数据源是完全独立的,基于架构的。 This configuration passes all unit tests and integration tests, but when I deploy it in Jetty, the repository operations fail with the below exception:
此配置通过了所有单元测试和集成测试,但是当我在Jetty中部署它时,存储库操作失败,但以下异常:
org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named my_transactionManager1' is defined: No unique PlatformTransactionManager bean found for qualifier 'my_transactionManager1'
at org.springframework.beans.factory.annotation.BeanFactoryAnnotationUtils.qualifiedBeanOfType(BeanFactoryAnnotationUtils.java:84)
at org.springframework.beans.factory.annotation.BeanFactoryAnnotationUtils.qualifiedBeanOfType(BeanFactoryAnnotationUtils.java:55)
at org.springframework.transaction.interceptor.TransactionAspectSupport.determineTransactionManager(TransactionAspectSupport.java:246)
at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:100)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172)
at org.springframework.aop.framework.Cglib2AopProxy$DynamicAdvisedInterceptor.intercept(Cglib2AopProxy.java:625)
at my.controller.Class$$EnhancerByCGLIB$$3976e5ef.myMethodCall(<generated>)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
persistence.xml persistence.xml
<persistence-unit name="pu1">
<properties>
<property name="hibernate.dialect" value="${hibernate.dialect}" />
<property name="hibernate.connection.url" value="${network.db.url}" />
<property name="hibernate.connection.driver_class" value="${hibernate.connection.driver_class}" />
<property name="hibernate.connection.username" value="{db.username}" />
<property name="hibernate.connection.password" value="{db.password}" />
<property name="hibernate.enable_lazy_load_no_trans" value="true"/>
<property name="hibernate.hbm2ddl.auto" value="${hibernate.hbm2ddl.auto}" />
<property name="hibernate.show_sql" value="false" />
</properties>
Looking at the logs, both datasources seems to behave sanely (until this error occurs). 查看日志,这两个数据源似乎行为正常(直到发生此错误)。 Below is the application context:
下面是应用程序上下文:
<?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:jdbc="http://www.springframework.org/schema/jdbc"
xmlns:tx="http://www.springframework.org/schema/tx" xmlns:jpa="http://www.springframework.org/schema/data/jpa"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/jdbc
http://www.springframework.org/schema/jdbc/spring-jdbc-3.0.xsd
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd
http://www.springframework.org/schema/data/jpa
http://www.springframework.org/schema/data/jpa/spring-jpa.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
<tx:annotation-driven transaction-manager="my_transactionManager1" />
<context:component-scan base-package="com.my.package"/>
<jpa:repositories
base-package="com.my.package" entity-manager-factory-ref="my_entityManagerFactory" transaction-manager-ref="my_transactionManager1">
</jpa:repositories>
<bean id="my_dataSource1" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver"/>
<property name="url" value="${my.db1.url}"/>
<property name="username" value="${db1.username}"/>
<property name="password" value="${db1.password}"/>
</bean>
<bean id="my_entityManagerFactory1"
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="persistenceUnitName" value="pu1" />
<property name="dataSource" ref="my_dataSource1" />
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
<property name="databasePlatform" value="${hibernate.dialect}"/>
<property name="generateDdl" value="false" />
<property name="database" value="HSQL"/>
</bean>
</property>
<property name="jpaProperties">
<props>
<prop key="hibernate.dialect">${hibernate.dialect}</prop>
</props>
</property>
</bean>
<bean id="my_transactionManager1" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="my_entityManagerFactory1" />
<property name="dataSource" ref="my_dataSource1" />
<qualifier value="my_transactionManager1"/>
<property name="persistenceUnitName" value="pu1"/>
</bean>
</beans>
My Service Class where I'm trying to inject the TransactionManager: 我要在其中注入TransactionManager的服务类:
Service
@Transactional(value="my_transactionManager1")
@PersistenceContext(unitName = "pu1", name="my_entityManagerFactory1")
public class MyServiceClass{
@Autowired
private Field myField
@Resource(name="my_transactionManager1")
private JpaTransactionManager my_transactionManager1;
/**
* Public no-arg constructor for bean initialization
*/
public MyServiceClass() {}
/**
* Protected IOC constructor for testing
*
* @param resultsService
*/
protected MyServiceClass(Field myField) {
this.myField = myField;
}
I have tried a lot of different approaches to work around this problem. 我尝试了许多不同的方法来解决此问题。 One thing that is often suggested for this situation is a single JTA XA TransactionManager, but I would like to avoid that, at least for this first pass.
在这种情况下,通常建议使用一个JTA XA TransactionManager,但至少在第一遍中,我想避免这种情况。 Another thing that is suggested is using an AbstractDataRoutingSource, but I don't really want that either.
建议的另一件事是使用AbstractDataRoutingSource,但我也不希望如此。 The approach I have seems tenable (if not optimal), because tests are passing and the application deploys without error.
我所采用的方法似乎是可行的(如果不是最佳的话),因为测试正在通过且应用程序部署没有错误。 Here is my web.xml (sorry for lengthy post):
这是我的web.xml(很长的帖子很抱歉):
<?xml version="1.0" encoding="UTF-8"?>
<web-app id="site" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
version="2.5">
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>
classpath:my-first-context-file.xml,
classpath:a-few-other-config-files.xml,
</param-value>
</context-param>
<listener>
<listener-class>
org.springframework.web.context.ContextLoaderListener
</listener-class>
<servlet>
<servlet-name>MyServeletName</servlet-name>
<servlet-class>
com.sun.jersey.spi.spring.container.servlet.SpringServlet
</servlet-class>
<init-param>
<param-name>
com.sun.jersey.config.property.packages
</param-name>
<param-value>com.my.package</param-value>
</init-param>
<init-param>
<param-name>com.sun.jersey.api.json.POJOMappingFeature</param-name>
<param-value>true</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
</load-on-startup>
</servlet>
<!--More servlets -->
<!-- Servlet mapping stuff -->
</web-app>
Any help at all would be much appreciated. 任何帮助将不胜感激。
Make sure, you have unique ids of beans. 确保您具有唯一的bean ID。 It seems like you have 2 transactionManager beans with id="my_entityManagerFactory1" Any way, you should add to annotation propagation value: @Transactional(propagation=Propagation.REQUIRED, value="my_entityManagerFactory1")
似乎您有2个id为“ my_entityManagerFactory1”的transactionManager bean,无论如何,都应添加到注释传播值:@Transactional(propagation = Propagation.REQUIRED,value =“ my_entityManagerFactory1”)
Similar problem (one entity in 2 databases) I have solved by inheritence: 我已经通过继承解决了类似的问题(2个数据库中的一个实体):
@MappedSuperclass
public class User{
private String name;
private String surname;
private String login;
private String password;
}
@Entity
public class Employee extends User{
//....
}
@Entity
public class CLient extends User{
//...
}
Employee and Client classes were in different subpackages of entity package. Employee和Client类位于实体包的不同子包中。 One sessionFaction scanned first subpackage, other sessionFactory scanned second one.
一个sessionFaction扫描了第一个子包,其他sessionFactory扫描了第二个子包。 I had two services with @Transaction annotation like above and serched both databases by one manager class.
我有两个带有上述@Transaction批注的服务,并通过一个管理器类对两个数据库进行了服务。 On application I used only User entity
在应用程序上,我仅使用了用户实体
我通过将两个数据库合并为一个来“解决”该问题。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.