多个SessionFactory配置因org.springframework.beans.factory.UnsatisfiedDependencyException异常而失败

时间:2015-09-24 16:02:29

标签: spring hibernate transactions annotations

我们的应用程序需要处理多个数据库。我们尝试通过Hibernate配置配置多个数据源,并为数据库1添加了两个配置,为数据库2添加了第二个配置。此配置失败,并出现以下异常

org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'DB1TransactionManager' defined in class path resource [org/npcc/ccms/config/db/HibernateConfig4DB1.class]: Unsatisfied dependency expressed through constructor argument with index 0 of type [org.hibernate.SessionFactory]: : No qualifying bean of type [org.hibernate.SessionFactory] is defined: expected single matching bean but found 2: AgrgtrSessionFactory,HRSessionFactory,StageSessionFactory; nested exception is org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type [org.hibernate.SessionFactory] is defined: expected single matching bean but found 3: DB1SessionFactory,DB2SessionFactory
org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:747)
    org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:462)
    org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:1094)
    org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:989)
    org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:504)
    org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:475)
    org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:302)
    org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:228)
    org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:298)
    org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:193)
    org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:703)
    org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:760)
    org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:482)
    org.springframework.web.servlet.FrameworkServlet.configureAndRefreshWebApplicationContext(FrameworkServlet.java:658)
    org.springframework.web.servlet.FrameworkServlet.initWebApplicationContext(FrameworkServlet.java:530)
    org.springframework.web.servlet.FrameworkServlet.initServletBean(FrameworkServlet.java:484)
    org.springframework.web.servlet.HttpServletBean.init(HttpServletBean.java:136)
    javax.servlet.GenericServlet.init(GenericServlet.java:160)
    org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:472)
    org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:99)
    org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:947)
    org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:408)
    org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1009)
    org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:589)
    org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:310)
    java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
    java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
    java.lang.Thread.run(Thread.java:745)

root cause

org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type [org.hibernate.SessionFactory] is defined: expected single matching bean but found 2: DB1SessionFactory,DB2SessionFactory
    org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:970)
    org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:858)
    org.springframework.beans.factory.support.ConstructorResolver.resolveAutowiredArgument(ConstructorResolver.java:811)
    org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:739)
    org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:462)
    org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:1094)
    org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:989)
    org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:504)
    org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:475)
    org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:302)
    org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:228)
    org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:298)
    org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:193)
    org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:703)
    org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:760)
    org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:482)
    org.springframework.web.servlet.FrameworkServlet.configureAndRefreshWebApplicationContext(FrameworkServlet.java:658)
    org.springframework.web.servlet.FrameworkServlet.initWebApplicationContext(FrameworkServlet.java:530)
    org.springframework.web.servlet.FrameworkServlet.initServletBean(FrameworkServlet.java:484)
    org.springframework.web.servlet.HttpServletBean.init(HttpServletBean.java:136)
    javax.servlet.GenericServlet.init(GenericServlet.java:160)
    org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:472)
    org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:99)
    org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:947)
    org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:408)
    org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1009)
    org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:589)
    org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:310)
    java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
    java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
    java.lang.Thread.run(Thread.java:745)

第一个数据库配置:

@Configuration
@EnableTransactionManagement
@ComponentScan({ "org.npcc.ccms.config" })
@PropertySource(value = { "classpath:application.properties" })
public class HibernateConfig4DB1 {
    final static Logger logger = LogManager.getLogger(HibernateConfig4DB1.class);

    @Autowired
    private Environment environment;

     @Bean(name="DB1SessionFactory")
    public LocalSessionFactoryBean db1SessionFactory() {
        LocalSessionFactoryBean sessionFactory = new LocalSessionFactoryBean();
        sessionFactory.setDataSource(dataSource());
        sessionFactory.setPackagesToScan(new String[] { "org.npcc.ccms.model.db1" });
        sessionFactory.setHibernateProperties(hibernateProperties());
        return sessionFactory;
     }

    @Bean(destroyMethod="")
    public DataSource dataSource() {
        JndiTemplate jndi = new JndiTemplate();
        DataSource dataSource = null;
        try {
            dataSource = (DataSource) jndi.lookup(environment.getRequiredProperty("datasource"));
        } catch (NamingException e) {
            logger.error("NamingException for java:comp/env/jdbc/ccms_cp1_orcl", e);
        }
        return dataSource;
    }

    private Properties hibernateProperties() {
        Properties properties = new Properties();
        properties.put("hibernate.dialect", environment.getRequiredProperty("hibernate.dialect"));
        properties.put("hibernate.show_sql", environment.getRequiredProperty("hibernate.show_sql"));
        properties.put("hibernate.format_sql", environment.getRequiredProperty("hibernate.format_sql"));
        return properties;        
    }

    @Bean(name="DB1TransactionManager")
    @Autowired
    @Qualifier("DB1SessionFactory")
    public HibernateTransactionManager db1TransactionManager(SessionFactory s) {
       HibernateTransactionManager txManager = new HibernateTransactionManager();
       txManager.setSessionFactory(s);
       return txManager;
    }
}

第二个数据库配置:

@Configuration
@EnableTransactionManagement
@ComponentScan({ "org.npcc.ccms.config" })
@PropertySource(value = { "classpath:application.properties" })
public class HibernateConfig4DB2 {
    final static Logger logger = LogManager.getLogger(HibernateConfig4DB2.class);

    @Autowired
    private Environment environment;

     @Bean(name="DB2SessionFactory")
    public LocalSessionFactoryBean db2SessionFactory() {
        LocalSessionFactoryBean sessionFactory = new LocalSessionFactoryBean();
        sessionFactory.setDataSource(dataSource());
        sessionFactory.setPackagesToScan(new String[] { "org.npcc.ccms.model.db2" });
        sessionFactory.setHibernateProperties(hibernateProperties());
        return sessionFactory;
     }

    @Bean(destroyMethod="")
    public DataSource dataSource() {
        JndiTemplate jndi = new JndiTemplate();
        DataSource dataSource = null;
        try {
            dataSource = (DataSource) jndi.lookup(environment.getRequiredProperty("datasource"));
        } catch (NamingException e) {
            logger.error("NamingException for java:comp/env/jdbc/ccms_cp1_orcl", e);
        }
        return dataSource;
    }

    private Properties hibernateProperties() {
        Properties properties = new Properties();
        properties.put("hibernate.dialect", environment.getRequiredProperty("hibernate.dialect"));
        properties.put("hibernate.show_sql", environment.getRequiredProperty("hibernate.show_sql"));
        properties.put("hibernate.format_sql", environment.getRequiredProperty("hibernate.format_sql"));
        return properties;        
    }

    @Bean(name="DB2TransactionManager")
    @Autowired
    @Qualifier("DB2SessionFactory")
    public HibernateTransactionManager db2TransactionManager(SessionFactory s) {
       HibernateTransactionManager txManager = new HibernateTransactionManager();
       txManager.setSessionFactory(s);
       return txManager;
    }
}

3 个答案:

答案 0 :(得分:5)

那是因为您在配置中定义了2 SessionFactory,Spring无法猜出要选择哪一个。

您可以自动装配您的sessionFactory并在@Bean

中使用它
@Autowired
@Qualifier("DB1SessionFactory")
private SessionFactory sessionFactory;

@Bean(name="DB1TransactionManager")
public HibernateTransactionManager db2TransactionManager() {
   HibernateTransactionManager txManager = new HibernateTransactionManager();
   txManager.setSessionFactory(this.sessionFactory);
   return txManager;
}

明确选择要使用的bean。

此外,您应该注意,只有一个配置需要保留@EnableTransactionManagement,而且您是组件扫描两次相同的包,这是不必要的。同样,您有2个@PropertySource具有相同的属性文件,只需要一个。

在您的情况下,我会使用您的{{RootHibernateConfig@Configuration@EnableTransactionManagement@ComponentScan({ "org.npcc.ccms.config" })注释+ @PropertySource(value = { "classpath:application.properties" })创建@Import 1}}和HibernateConfig4DB1

您可以从transactionManager beans方法中删除HibernateConfig4DB2@Autowired注释。不要忘记在代码中明确使用所需的transactionManager。

请参阅:http://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/transaction/annotation/Transactional.html

Spring - Is it possible to use multiple transaction managers in the same application?

答案 1 :(得分:0)

我遇到了同样的问题。按照以下方式解决

@Bean(name = "rebootSessionFactory")
public LocalSessionFactoryBean sessionFactory() {

    LocalSessionFactoryBean sessionFactory = new LocalSessionFactoryBean();
    sessionFactory.setDataSource(dataSource());
    sessionFactory.setPackagesToScan(
            new String[]
                    {
                            "com.ra.reboot.b.persistence.entity",
                            "com.ra.reboot.bl.persistence.entity",
                            "com.ra.reboot.bla.persistence.entity",
                            "com.ra.reboot.blaBla.persistence.entity"

                    });
    sessionFactory.setHibernateProperties(hibernateProperties());
    return sessionFactory;

}


@Bean(name="rebootTransactionManager")
public HibernateTransactionManager transactionManager() {
    HibernateTransactionManager txManager = new HibernateTransactionManager();

    txManager.setSessionFactory(sessionFactory().getObject());
    return txManager;
}


private Properties hibernateProperties() {

    Properties hibernateProperties = new Properties();
    hibernateProperties.setProperty("hibernate.cache.use_second_level_cache", "true");
    hibernateProperties.setProperty("hibernate.cache.region.factory_class", "org.hibernate.cache.ehcache.SingletonEhCacheRegionFactory");
    hibernateProperties.setProperty("hibernate.cache.use_query_cache", "true");
    hibernateProperties.setProperty("org.hibernate.envers.audit_table_prefix", "history");
    hibernateProperties.setProperty("org.hibernate.envers.audit_table_suffix", "_audit");
    hibernateProperties.setProperty("hibernate.jdbc.batch_size", "500");

    return hibernateProperties;
}

   @Bean
public HibernateExceptionTranslator hibernateExceptionTranslator() {
    return new HibernateExceptionTranslator();
}



@Bean
public DataSource dataSource() {
    Properties jdbcProperties = this.getJdbcPropertise();
    DriverManagerDataSource dataSource = new DriverManagerDataSource();
    dataSource.setDriverClassName(jdbcProperties.getProperty("jdbc.drive.class"));
    dataSource.setUrl(jdbcProperties.getProperty("jdbc.database.url"));
    dataSource.setUsername(jdbcProperties.getProperty("jdbc.database.username"));
    dataSource.setPassword(jdbcProperties.getProperty("jdbc.database.password"));
    return dataSource;
}


private Properties getJdbcPropertise() {
    InputStream inputStream = RarebootDataSourceConfig.class.getClassLoader().getResourceAsStream("dev.jdbc.properties");
    Properties jdbcProperties = new Properties();
    try {
        jdbcProperties.load(inputStream);
    } catch (NullPointerException IOException) {
        System.out.println("dev.jdbc.properties not Found");
        throw new RuntimeException();
    } catch (IOException e) {
        System.out.println("dev.jdbc.properties not Found");
        throw new RuntimeException();
    }
    return jdbcProperties;
}

这是配置文件。然后在BaseDao

@Autowired
@Qualifier("rebootSessionFactory")
public SessionFactory sessionFactory;

public SessionFactory getSessionFactory() {
    return sessionFactory;
}

public Session getSession() {
    return this.sessionFactory.getCurrentSession();
}

为我服务

import org.springframework.transaction.annotation.Transactional;

@Service
@Transactional(value = "rebootTransactionManager")
public class ClientLeadInfoService {
 ...
}

确保您正在使用此:

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-tx</artifactId>
    <version>5.0.2.RELEASE</version>
</dependency>

所以我有2个配置文件(这里我只发布一个示例文件)。我必须告诉我的BaseDao我正在使用哪个会话工厂。在我的服务中,我必须告诉我正在使用哪个事务管理器。

答案 2 :(得分:0)

它是由于继承而发生的。有BaseClass类(基类)和DerrivedClass类(从BaseClass扩展)。当我使用@Autowire注释时,它给出了一个错误,原因是有2个对象,即Class BaseClass和Class DerrivedClass。

我使用@Resource注释代替@Autowire,如下所示 @Resource(name =“ derrivedClass”) DerrivedClass testObj;

看来,Spring Boot会创建名称与骆驼字母中的类相同的bean。例如如果我的班级是TestClass,那么Bean名称将是“ testClass”