Spring + 2 Hibernate数据源+ 2个TransactionManagers:NoSuchBeanDefinitionException

时间:2013-07-08 14:03:30

标签: java spring hibernate jpa jetty

我有一个带有两个Hibernate数据源的Spring Web应用程序,它们由两个独立的事务管理器管理。数据源完全独立,以模式方式。此配置通过了所有单元测试和集成测试,但是当我在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-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>

查看日志,两个数据源似乎都表现得很好(直到发生此错误)。以下是应用程序上下文:

<?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>

我正在尝试注入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;
}

我尝试了很多不同的方法来解决这个问题。对于这种情况经常建议的一件事是单个JTA XA TransactionManager,但我想避免这种情况,至少对于第一次传递。建议的另一件事是使用AbstractDataRoutingSource,但我也不是真的想要它。我的方法似乎是可行的(如果不是最佳的),因为测试正在通过,应用程序部署没有错误。这是我的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>

任何帮助都会非常感激。

2 个答案:

答案 0 :(得分:0)

确保您拥有独特的豆类ID。看起来你有2个事务管理器bean,id =“my_entityManagerFactory1” 无论如何,您应该添加到注释传播值:     @Transactional(propagation = Propagation.REQUIRED,value =“my_entityManagerFactory1”)

类似的问题(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和Client类位于实体包的不同子包中。 一个sessionFaction扫描了第一个子包,其他sessionFactory扫描了第二个子包。 我有两个像上面这样的@Transaction注释服务,并且通过一个管理器类来为两个数据库提供服务。 在应用程序上我只使用了用户实体

答案 1 :(得分:-1)

我通过将两个数据库合二为一来解决了这个问题。