我们的应用程序需要处理多个数据库。我们尝试通过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;
}
}
答案 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。
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”