java - 具有多个数据源的休眠配置类
问题描述
我们的应用程序需要处理多个数据库。我们尝试通过 Hibernate 配置配置多个数据源,并添加了两个配置,一个用于数据库 1,第二个用于数据库 2。此配置失败并出现以下异常
WARNING: Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'mainController': Unsatisfied dependency expressed through field 'dataDAO'; nested exception is org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'dataDAO': Unsatisfied dependency expressed through field 'sessionFactory'; nested exception is org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type 'org.hibernate.SessionFactory' available: expected single matching bean but found 2: sessionFactory1,sessionFactory2
Nov 29, 2019 5:08:11 PM org.springframework.web.context.ContextLoader initWebApplicationContext
SEVERE: Context initialization failed
org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'mainController': Unsatisfied dependency expressed through field 'dataDAO'; nested exception is org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'dataDAO': Unsatisfied dependency expressed through field 'sessionFactory'; nested exception is org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type 'org.hibernate.SessionFactory' available: expected single matching bean but found 2: sessionFactory1,sessionFactory2
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:596)
这是我的配置类:
package com.pack1.config;
import java.beans.PropertyVetoException;
import java.sql.SQLException;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;
import java.util.logging.Logger;
import javax.sql.DataSource;
import org.hibernate.SessionFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
import org.springframework.context.annotation.PropertySources;
import org.springframework.core.env.Environment;
import org.springframework.orm.hibernate5.HibernateTransactionManager;
import org.springframework.orm.hibernate5.LocalSessionFactoryBean;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import org.springframework.web.servlet.view.InternalResourceViewResolver;
import com.mchange.v2.c3p0.ComboPooledDataSource;
import com.pack1.routing.MyRoutingDataSource;
@Configuration
@ComponentScan("com.pack1")
@EnableWebMvc
@EnableTransactionManagement
// Load to Environment
@PropertySources({@PropertySource("classpath:ds/datasource-cfg.properties")})
public class ApplicationContextConfig implements WebMvcConfigurer
{
// The Environment class serves as the property holder
// and stores all the properties loaded by the @PropertySource
@Autowired
private Environment env;
private Logger logger = Logger.getLogger(getClass().getName());
@Bean(name = "viewResolver")
public InternalResourceViewResolver getViewResolver() {
InternalResourceViewResolver viewResolver = new InternalResourceViewResolver();
viewResolver.setPrefix("/WEB-INF/pages/");
viewResolver.setSuffix(".jsp");
return viewResolver;
}
// Returns Routing DataSource (MyRoutingDataSource)
@Autowired
@Bean(name = "dataSource")
public DataSource getDataSource(DataSource dataSource1, DataSource dataSource2) {
System.out.println("## Create DataSource from dataSource1 & dataSource2");
MyRoutingDataSource dataSource = new MyRoutingDataSource();
Map<Object, Object> dsMap = new HashMap<Object, Object>();
dsMap.put("PUBLISHER_DS", dataSource1);
dsMap.put("ADVERTISER_DS", dataSource2);
dataSource.setTargetDataSources(dsMap);
return dataSource;
}
@Bean(name = "dataSource1")
public DataSource getDataSource1() throws SQLException, PropertyVetoException {
ComboPooledDataSource dataSource = new ComboPooledDataSource();
// See: datasouce-cfg.properties
dataSource.setDriverClass(env.getProperty("ds.database-driver1"));
dataSource.setJdbcUrl(env.getProperty("ds.url1"));
dataSource.setUser(env.getProperty("ds.username1"));
dataSource.setPassword(env.getProperty("ds.password1"));
System.out.println("## getDataSource1: " + dataSource);
return dataSource;
}
private Properties getHibernateProperties1()
{
// set hibernate properties
Properties props = new Properties();
props.setProperty("ds.hibernate.dialect1", env.getProperty("ds.hibernate.dialect1"));
props.setProperty("ds.hibernate.show_sql1", env.getProperty("ds.hibernate.show_sql1"));
return props;
}
// need a helper method
// read environment property and convert to int
private int getIntProperty1(String propName) {
String propVal = env.getProperty(propName);
// now convert to int
int intPropVal = Integer.parseInt(propVal);
return intPropVal;
}
@Bean
public LocalSessionFactoryBean sessionFactory1() throws SQLException, PropertyVetoException{
// create session factorys
LocalSessionFactoryBean sessionFactory = new LocalSessionFactoryBean();
// set the properties
sessionFactory.setDataSource(getDataSource1());
sessionFactory.setPackagesToScan(env.getProperty("ds.hibernate.packagesToScan1"));
sessionFactory.setHibernateProperties(getHibernateProperties1());
return sessionFactory;
}
@Autowired
@Bean(name = "transactionManager")
public HibernateTransactionManager getTransactionManager1(SessionFactory sessionFactory1) {
// setup transaction manager based on session factory
HibernateTransactionManager txManager = new HibernateTransactionManager();
txManager.setSessionFactory(sessionFactory1);
return txManager;
}
@Bean(name = "dataSource2")
public DataSource getDataSource2() throws SQLException, PropertyVetoException {
ComboPooledDataSource dataSource = new ComboPooledDataSource();
// See: datasouce-cfg.properties
dataSource.setDriverClass(env.getProperty("ds.database-driver2"));
dataSource.setJdbcUrl(env.getProperty("ds.url2"));
dataSource.setUser(env.getProperty("ds.username2"));
dataSource.setPassword(env.getProperty("ds.password2"));
System.out.println("## getDataSource2: " + dataSource);
return dataSource;
}
private Properties getHibernateProperties2()
{
// set hibernate properties
Properties props = new Properties();
props.setProperty("ds.hibernate.dialect2", env.getProperty("ds.hibernate.dialect2"));
props.setProperty("ds.hibernate.show_sql2", env.getProperty("ds.hibernate.show_sql2"));
return props;
}
// need a helper method
// read environment property and convert to int
private int getIntProperty2(String propName) {
String propVal = env.getProperty(propName);
// now convert to int
int intPropVal = Integer.parseInt(propVal);
return intPropVal;
}
@Bean
public LocalSessionFactoryBean sessionFactory2() throws SQLException, PropertyVetoException{
// create session factorys
LocalSessionFactoryBean sessionFactory1 = new LocalSessionFactoryBean();
// set the properties
sessionFactory1.setDataSource(getDataSource2());
sessionFactory1.setPackagesToScan(env.getProperty("ds.hibernate.packagesToScan2"));
sessionFactory1.setHibernateProperties(getHibernateProperties2());
return sessionFactory1;
}
@Autowired
@Bean(name = "transactionManager")
public HibernateTransactionManager getTransactionManage2(SessionFactory sessionFactory1) {
// setup transaction manager based on session factory
HibernateTransactionManager txManager = new HibernateTransactionManager();
txManager.setSessionFactory(sessionFactory1);
return txManager;
}
}
道类:
package com.pack1.dao;
import org.hibernate.SessionFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.jdbc.core.support.JdbcDaoSupport;
import org.springframework.stereotype.Repository;
@Repository
public class DataDAO extends JdbcDaoSupport {
@Autowired
@Qualifier(value="t1")
private SessionFactory firstDBSessionFactory;
public List<Publisher> queryPublishers() {
// get the current hibernate session
Session currentSession = firstDBSessionFactory.getCurrentSession();
// create a query
Query<Publisher> theQuery =
currentSession.createQuery("from Publisher", Publisher.class);
// execute query and get result list
List<Publisher> customers = theQuery.getResultList();
// return the results
return customers;
return customers;
}
@Autowired
@Qualifier(value="t2")
private SessionFactory secondDBSessionFactory;
@Transactional(propagation= Propagation.REQUIRED, readOnly=true, value="t2")
public List<Advertiser> queryAdvertisers() {
// get the current hibernate session
Session currentSession = secondDBSessionFactory.getCurrentSession();
// create a query
Query<Advertiser> theQuery =
currentSession.createQuery("from Advertiser", Advertiser.class);
// execute query and get result list
List<Advertiser> customers = theQuery.getResultList();
// return the results
return customers;
}
}
public List<String> queryDashboard() {
return null;
}
}
属性文件:
# DataSource (PUBLISHER System).
ds.database-driver1=com.mysql.jdbc.Driver
ds.url1=jdbc:mysql://127.0.0.1:3306/pan_db
ds.username1=hbstudent
ds.password1=hbstudent
# DataSource (ADVERTISER System).
ds.database-driver2=com.mysql.jdbc.Driver
ds.url2=jdbc:mysql://127.0.0.1:3306/voter_db
ds.username2=hbstudent
ds.password2=hbstudent
#
# Hibernate properties1
#
ds.hibernate.dialect1=org.hibernate.dialect.MySQLDialect
ds.hibernate.show_sql1=true
ds.hibernate.hbm2ddl.auto1=update
#
# Hibernate properties2
#
ds.hibernate.dialect2=org.hibernate.dialect.MySQLDialect
ds.hibernate.show_sql2=true
ds.hibernate.hbm2ddl.auto2=update
SpringWebAppInitializer 类:
package com.pack1.config;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.ServletRegistration.Dynamic;
import org.springframework.web.WebApplicationInitializer;
import org.springframework.web.context.support.AnnotationConfigWebApplicationContext;
import org.springframework.web.filter.CharacterEncodingFilter;
import org.springframework.web.servlet.DispatcherServlet;
public class SpringWebAppInitializer implements WebApplicationInitializer
{
@Override
public void onStartup(ServletContext servletContext) throws ServletException {
AnnotationConfigWebApplicationContext ctx = new AnnotationConfigWebApplicationContext();
ctx.register(ApplicationContextConfig.class);
ctx.setServletContext(servletContext); // ②
Dynamic servlet = servletContext.addServlet("dispatcher",new DispatcherServlet(ctx)); // ③
servlet.addMapping("/*");
servlet.setLoadOnStartup(1);
servletContext.addFilter("name", CharacterEncodingFilter.class)
.addMappingForUrlPatterns(null, false, "/*");
}
/*@Override
public void onStartup(ServletContext servletContext) throws ServletException
{
AnnotationConfigWebApplicationContext appContext = new AnnotationConfigWebApplicationContext();
appContext.register(ApplicationContextConfig.class);
ServletRegistration.Dynamic dispatcher = servletContext.addServlet("SpringDispatcher",
new DispatcherServlet(appContext));
dispatcher.setLoadOnStartup(1);
dispatcher.addMapping("/");
//
dispatcher.setInitParameter("contextClass", appContext.getClass().getName());
servletContext.addListener(new ContextLoaderListener(appContext));
// UTF8 Charactor Filter.
FilterRegistration.Dynamic fr = servletContext.addFilter("encodingFilter", CharacterEncodingFilter.class);
fr.setInitParameter("encoding", "UTF-8");
fr.setInitParameter("forceEncoding", "true");
fr.addMappingForUrlPatterns(null, true, "/*");
}*/
}
WebMvcConfigurerAdapter 类:
package com.pack1.config;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.DefaultServletHandlerConfigurer;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
import com.pack1.intercepter.DataSourceIntercepter;
@Configuration
@EnableWebMvc
public class WebMvcConfig extends WebMvcConfigurerAdapter{
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry)
{
// Default..
}
@Override
public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
configurer.enable();
}
//
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new DataSourceIntercepter())//
.addPathPatterns("/publisher/*", "/advertiser/*");
}
}
以下例外是:
INFO: Server startup in [8,376] milliseconds
Dec 05, 2019 12:05:18 PM org.springframework.web.servlet.DispatcherServlet noHandlerFound
WARNING: No mapping for GET /multiple_DB1/
Dec 05, 2019 12:05:22 PM org.springframework.web.servlet.DispatcherServlet noHandlerFound
WARNING: No mapping for GET /multiple_DB1/
Dec 05, 2019 12:05:23 PM org.springframework.web.servlet.DispatcherServlet noHandlerFound
WARNING: No mapping for GET /multiple_DB1/
我是在 Spring MVC 中使用多个数据源的新手。请帮助我在 Hibernate Configuration 类中编码。
解决方案
每个数据库都需要多个配置文件,其中一个需要声明为Primary
. 我正在为您提供一些示例,以了解您需要什么。
PrimaryDB
被声明为项目的主数据库。Primary 表示默认情况下 JPA 将在主数据库上执行。
@Configuration
@EnableTransactionManagement
@EnableJpaRepositories(entityManagerFactoryRef = "primaryEntityManagerFactory",
basePackages = {"com.example.repositories.primary"})
public class PrimaryDBConfig {
@Primary
@Bean(name = "primaryDatasource")
@ConfigurationProperties(prefix = "primary.datasource")
public DataSource dataSource() {
return DataSourceBuilder.create().build();
}
@Primary
@Bean(name = "primaryEntityManagerFactory")
public LocalContainerEntityManagerFactoryBean entityManagerFactory(
EntityManagerFactoryBuilder builder, @Qualifier("primaryDatasource") DataSource dataSource) {
return builder.dataSource(dataSource).packages("com.example.entities.primary")
.persistenceUnit("primary").build();
}
@Primary
@Bean(name = "primaryTransactionManager")
public PlatformTransactionManager transactionManager(
@Qualifier("primaryEntityManagerFactory") EntityManagerFactory entityManagerFactory) {
return new JpaTransactionManager(entityManagerFactory);
}
}
关于我们的第二个数据库的第二个配置文件FooDB
@Configuration
@EnableTransactionManagement
@EnableJpaRepositories(entityManagerFactoryRef = "fooEntityManagerFactory",
basePackages = {"com.example.repositories.foo"})
public class FooDBConfig {
@Bean(name = "fooDatasource")
@ConfigurationProperties(prefix = "foo.datasource")
public DataSource dataSource() {
return DataSourceBuilder.create().build();
}
@Bean(name = "fooEntityManagerFactory")
public LocalContainerEntityManagerFactoryBean entityManagerFactory(
EntityManagerFactoryBuilder builder, @Qualifier("fooDatasource") DataSource dataSource) {
return builder.dataSource(dataSource).packages("com.example.entities.crf")
.persistenceUnit("foo").build();
}
@Bean(name = "fooTransactionManager")
public PlatformTransactionManager transactionManager(
@Qualifier("fooEntityManagerFactory") EntityManagerFactory entityManagerFactory) {
return new JpaTransactionManager(entityManagerFactory);
}
}
此外,您还需要在 上添加以下内容application.properties
,因为 Spring 会监听默认的数据源配置。
primary.datasource.url= URL
primary.datasource.username=username
primary.datasource.password=password
foo.datasource.url=URL
foo.datasource.username=username
foo.datasource.password=password
推荐阅读
- c# - ASP.NET Core 模拟服务仅在一个请求的范围内
- php - 如果客户购买了一些特定的产品,那么我想将其他条件放入其中
- java - Spring 自定义身份验证令牌从未 GCed
- java - 如何在 Android 上将位图图像转换为 TensorImage?
- shap - 获取使用 kNN 进行的预测的 SHAP 值
- database - INSERT INTO 错误和 PLS-00231 错误函数可能无法在 SQL 中使用
- javascript - 丢弃 child 会触发 parent 的“drop”事件侦听器。我想用特定于子的“drop”覆盖该事件侦听器
- python - 在 tensorflow 中实现 KL 预热:回调中的 tf.keras.backend.variable 在 epochs 上不稳定
- modelica - 通过从 Dymola 导出到 FMU,所有参数默认为“可调”,但应为“固定”
- python - Python tkinter - 自动单击 Treeview 中的选定项目