多个数据源的 Hikaricp 配置
Posted
技术标签:
【中文标题】多个数据源的 Hikaricp 配置【英文标题】:Hikaricp configuration for multiple datasources 【发布时间】:2019-01-09 08:04:34 【问题描述】:我有一个多数据库应用程序。用户可以在登录页面选择数据库。
然后数据库正在路由选定的数据库,感谢 Spring 的 AbstractRoutingDataSource。
我想使用 HikariCP,但它需要 dataSourceUrl。但我的数据源 URL 会动态变化。如何为多个数据库配置 Hikaricp?
文件application.properties:
#database1 properties
app.database1.connection.url = url1
app.database1.connection.username = sameusername
app.database1.connection.password = samepassword
#database2 properties
app.database2.connection.url = url2
app.database2.connection.username = sameusername
app.database2.connection.password = samepassword
我的Datasource配置类示例:
public class DataSourceConfiguration
@Autowired(required = false)
private PersistenceUnitManager persistenceUnitManager;
@Bean
@ConfigurationProperties(prefix = "app.database1.connection")
public DataSource database1DataSource()
return DataSourceBuilder.create().build();
@Bean
@ConfigurationProperties(prefix = "app.database2.connection")
public DataSource database2DataSource()
return DataSourceBuilder.create().build();
@Bean
@Primary
public DataSource appDataSource()
DataSourceRouter router = new DataSourceRouter();
final HashMap<Object, Object> map = new HashMap<>(3);
map.put(DatabaseEnvironment.DATABASE1, database1DataSource());
map.put(DatabaseEnvironment.DATABASE2, database2DataSource());
router.setTargetDataSources(map);
return router;
@Bean
@Primary
@ConfigurationProperties("app.connection.jpa")
public JpaProperties appJpaProperties()
return new JpaProperties();
private JpaVendorAdapter createJpaVendorAdapter(JpaProperties jpaProperties)
AbstractJpaVendorAdapter adapter = new HibernateJpaVendorAdapter();
adapter.setShowSql(jpaProperties.isShowSql());
adapter.setDatabase(jpaProperties.getDatabase());
adapter.setDatabasePlatform(jpaProperties.getDatabasePlatform());
adapter.setGenerateDdl(jpaProperties.isGenerateDdl());
return adapter;
我的会话范围类而不是上下文持有者:
@Component
@Scope(value = "session", proxyMode = ScopedProxyMode.TARGET_CLASS)
public class PreferredDatabaseSession implements Serializable
/**
*
*/
private static final long serialVersionUID = 1L;
private DatabaseEnvironment preferredDb;
public DatabaseEnvironment getPreferredDb()
return preferredDb;
public void setPreferredDb(DatabaseEnvironment preferredDb)
this.preferredDb = preferredDb;
【问题讨论】:
你说DB url动态变化是什么意思? application.properties 文件中的url1
、url2
等是常量吧?
url1 和 url2 ara 常量。但是,当用户选择 database1 AbstractRoutingDataSource 将用户路由到 url1 时,当他选择 database2 时,它会转到 url2
【参考方案1】:
如果我正确理解您的要求,您打算定义两个数据源,并且对于给定请求,您希望根据某些条件将查询路由到特定数据源。
解决办法是:
文件application.properties
#database1 properties
app.database1.connection.url = url1
app.database1.connection.username = username1
app.database1.connection.password = password1
#database2 properties
app.database2.connection.url = url2
app.database2.connection.username = username2
app.database2.connection.password = password2
#default
default.datasource.key=dataSource1
文件 CommonRoutingDataSource.java
public class CommonRoutingDataSource extends AbstractRoutingDataSource
@Override
protected Object determineCurrentLookupKey()
return DataSourceContextHolder.getDataSourceName();
public void initDataSources(final DataSource dataSource1, final DataSource dataSource2,
final String defaultDataSourceKey)
final Map<Object, Object> dataSourceMap = new HashMap<Object, Object>();
dataSourceMap.put("dataSource1", dataSource1);
dataSourceMap.put("dataSource2", dataSource2);
this.setDefaultTargetDataSource(dataSourceMap.get(defaultDataSourceKey));
this.setTargetDataSources(dataSourceMap);
文件 DataSourceContextHolder.java
public class DataSourceContextHolder
private static final ThreadLocal<String> contextHolder = new ThreadLocal<>();
private DataSourceContextHolder()
// Private no-op constructor
public static final void setDataSourceName(final String dataSourceName)
Assert.notNull(dataSourceName, "dataSourceName cannot be null");
contextHolder.set(dataSourceName);
public static final String getDataSourceName()
return contextHolder.get();
public static final void clearDataSourceName()
contextHolder.remove();
文件 DataSourceConfig.java
public class DataSourceConfig
@Autowired
private Environment env;
@Autowired
@Bean(name = "dataSource")
public DataSource getDataSource(final DataSource dataSource1, final DataSource dataSource2)
final CommonRoutingDataSource dataSource = new CommonRoutingDataSource();
dataSource.initDataSources(dataSource1, dataSource2, env.getProperty("default.datasource.key"));
return dataSource;
@Bean(name = "dataSource1")
public DataSource getDataSource1() throws SQLException
// The exact DataSource class imported shall be as per your requirement - HikariCP, or Tomcat etc.
final DataSource dataSource = new DataSource();
dataSource.setDriverClassName();
dataSource.setUrl(env.getProperty("app.database1.connection.url"));
// Set all data source attributes from the application.properties file
return dataSource;
@Bean(name = "dataSource2")
public DataSource getDataSource2() throws SQLException
// The exact DataSource class imported shall be as per your requirement - HikariCP, or Tomcat etc.
final DataSource dataSource = new DataSource();
dataSource.setDriverClassName();
dataSource.setUrl(env.getProperty("app.database2.connection.url"));
// set all data source attributes from the application.properties file
return dataSource;
现在,在您的代码中的某处(Aspect 或 Controller),您需要有条件地动态设置数据源:
DataSourceContextHolder.setDataSourceName("dataSource1");
注意:最好将数据源名称声明为枚举,而不是字符串“dataSource1”、“dataSource2”等。
【讨论】:
我没有在 DataSourceContextHolder 上使用 ThreadLocal。而不是它,我使用 Session 范围类。我将它附加到问题正文中。以上是关于多个数据源的 Hikaricp 配置的主要内容,如果未能解决你的问题,请参考以下文章
如何使用 HikariCP 在 Jboss 中配置 JNDI 数据源?
为啥HikariCP被号称为性能最好的Java数据库连接池,如何配置使用
为啥HikariCP被号称为性能最好的Java数据库连接池,如何配置使用