文章目录
- 前言
- 一、基本概念
-
- [1.1 什么是多数据源?](#1.1 什么是多数据源?)
- [1.2 为什么要使用多数据源?](#1.2 为什么要使用多数据源?)
- [二、如何在 Spring Boot 中整合多数据源?](#二、如何在 Spring Boot 中整合多数据源?)
-
- [2.1 基本配置](#2.1 基本配置)
- [2.2 项目代码](#2.2 项目代码)
- [2.3 注意事项](#2.3 注意事项)
前言
在实际的开发工作中,我们经常会遇到需要整合多个数据源的情况,比如同时连接多个数据库、读写分离、跨数据库查询等。本文将介绍如何使用Spring Boot来实现多数据源的整合,对于刚刚接触开发的小伙伴可能有一些帮助。
一、基本概念
1.1 什么是多数据源?
在一个应用程序中使用多个数据源意味着我们需要在不同的数据源之间进行切换,以便从不同的数据源中获取数据。多数据源可以是关系数据库、NoSQL 数据库、平面文件、XML 文件等。在一个应用程序中使用多数据源的好处是,我们可以根据应用程序的需求选择最合适的数据源,从而提高应用程序的性能和可扩展性。
1.2 为什么要使用多数据源?
在一个应用程序中使用多数据源的好处有很多,其中一些是:
- 可以根据应用程序的需求选择最合适的数据源,从而提高应用程序的性能和可扩展性。
- 可以减少单一数据源所带来的风险,例如单点故障。
- 可以更好地支持数据的隔离和数据的安全性。
- 可以更好地支持不同的业务需求。
二、如何在 Spring Boot 中整合多数据源?
2.1 基本配置
接下来的整合示例,我将以实际项目整合示例来介绍,项目中是mysql和phoenix多数据源,那么接下来详细描述一下,因为项目中整合了MybatisPlus,所以也会有一些相关的配置,首先,我们需要在pom.xml文件中添加相应的依赖项。以下是常用的数据源依赖项:
xml
<!-- 数据源 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<!-- MySQL 数据库 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<!-- phoenix 数据库 -->
<dependency>
<groupId>org.apache.phoenix</groupId>
<artifactId>phoenix-core</artifactId>
</dependency>
<!-- mybatis-plus -->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
</dependency>
接下来,我们需要在application.properties或application.yml文件中配置各个数据源的连接信息。以下是示例配置:
yaml
#数据库配置
datasource:
#mysql数据源配置
mysql:
type: com.zaxxer.hikari.HikariDataSource
jdbc-url: jdbc:p6spy:mysql://xxxx:3306/xxxx?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=GMT%2B8&allowPublicKeyRetrieval=true
username: xxxx
password: xxxxx
# Hikari 连接池配置
# 最小空闲连接数量
hikari:
minimum-idle: 5
# 空闲连接存活最大时间,默认600000(10分钟)
idle-timeout: 180000
# 连接池最大连接数,默认是10
maximum-pool-size: 10
# 此属性控制从池返回的连接的默认自动提交行为,默认值:true
auto-commit: true
# 连接池名称
pool-name: xxxx-HikariCP
# 此属性控制池中连接的最长生命周期,值0表示无限生命周期,默认1800000即30分钟
max-lifetime: 1800000
# 数据库连接超时时间,默认30秒,即30000
connection-timeout: 30000
connection-test-query: SELECT 1
#phoenix数据源配置
phoenix:
driver: org.apache.phoenix.jdbc.PhoenixDriver
jdbcUrl: jdbc:phoenix:xxxxx:xxxx
user:
password:
connectionProperties:
isNamespaceMappingEnabled: true
mapSystemTablesToNamespace: true
schema: 'xxxxxx'
maximumPoolSize: 128
maxLifetime: 1200000
之后,我们需要创建多个数据源的配置类,以及一些基础的配置。以下是示例代码:
java
@EnableTransactionManagement
@Configuration
@MapperScan("com.xxxx.mapper")
public class DataSourceConfig {
@Autowired
private PhoenixProperties phoenixProperties;
@Bean
public PaginationInterceptor paginationInterceptor() {
return new PaginationInterceptor().setDialectType("mysql");
}
@Bean(name = "mysqlDateSource")
@ConfigurationProperties(prefix = "spring.datasource.mysql")
public HikariDataSource mysqlDateSource() {
return DataSourceBuilder.create().type(HikariDataSource.class).build();
}
@Bean(name = "phoenixDataSource")
public HikariDataSource phoenixDataSource() {
HikariDataSource dataSource = new HikariDataSource();
dataSource.setDriverClassName(phoenixProperties.getDriver());
dataSource.setJdbcUrl(phoenixProperties.getJdbcUrl());
dataSource.setUsername(phoenixProperties.getUser());
dataSource.setPassword(phoenixProperties.getPassword());
Properties properties = new Properties();
properties.setProperty("phoenix.schema.isNamespaceMappingEnabled", phoenixProperties.getIsNamespaceMappingEnabled());
properties.setProperty("phoenix.schema.mapSystemTablesToNamespace", phoenixProperties.getMapSystemTablesToNamespace());
properties.setProperty("schema", phoenixProperties.getSchema());
properties.setProperty("maximum-pool-size", phoenixProperties.getMaximumPoolSize());
properties.setProperty("max-lifetime", phoenixProperties.getMaxLifetime());
dataSource.setDataSourceProperties(properties);
return dataSource;
}
/**
* 动态数据源配置
*
* @return DataSource
*/
@Bean
@Primary
public DataSource multipleDataSource(@Qualifier("mysqlDateSource") DataSource mysqlDateSource, @Qualifier("phoenixDataSource") DataSource phoenixDataSource) {
MultipleDataSource multipleDataSource = new MultipleDataSource();
Map<Object, Object> targetDataSources = Maps.newHashMap();
targetDataSources.put(DataSourceEnum.MYSQL.getValue(), mysqlDateSource);
targetDataSources.put(DataSourceEnum.PHOENIX.getValue(), phoenixDataSource);
//添加数据源
multipleDataSource.setTargetDataSources(targetDataSources);
//设置默认数据源
multipleDataSource.setDefaultTargetDataSource(mysqlDateSource);
return multipleDataSource;
}
@Bean(name = "sqlSessionFactory")
public SqlSessionFactory sqlSessionFactory() throws Exception {
MybatisSqlSessionFactoryBean sqlSessionFactory = new MybatisSqlSessionFactoryBean();
sqlSessionFactory.setDataSource(multipleDataSource(mysqlDateSource(), phoenixDataSource()));
ResourceLoader loader = new DefaultResourceLoader();
String resource = "classpath:mybatis-config.xml";
sqlSessionFactory.setConfigLocation(loader.getResource(resource));
ResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
sqlSessionFactory.setMapperLocations(resolver.getResources("classpath*:/mapper/*.xml"));
sqlSessionFactory.setTypeAliasesPackage("com.huitongjy.oms.web.entity");
sqlSessionFactory.setTypeEnumsPackage("com.huitongjy.oms.common.enums");
//关键代码 设置 MyBatis-Plus 分页插件
Interceptor[] plugins = {paginationInterceptor()};
sqlSessionFactory.setPlugins(plugins);
return sqlSessionFactory.getObject();
}
}
MultipleDataSource类
java
public class MultipleDataSource extends AbstractRoutingDataSource {
@Override
protected Object determineCurrentLookupKey() {
return DataSourceContextHolder.getDataSource();
}
}
class DataSourceContextHolder {
private static final ThreadLocal<String> CONTEXT_HOLDER = new InheritableThreadLocal<>();
/**
* 设置数据源
*
* @param db String
*/
static void setDataSource(String db) {
CONTEXT_HOLDER.set(db);
}
/**
* 取得当前数据源
*
* @return String
*/
static String getDataSource() {
return CONTEXT_HOLDER.get();
}
/**
* 清除上下文数据
*/
static void clear() {
CONTEXT_HOLDER.remove();
}
}
mybatis-config.xml的配置如下:
xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<settings>
<setting name="cacheEnabled" value="false"/>
<setting name="lazyLoadingEnabled" value="true"/>
<setting name="multipleResultSetsEnabled" value="true"/>
<setting name="useColumnLabel" value="true"/>
<setting name="useGeneratedKeys" value="false"/>
<setting name="autoMappingBehavior" value="PARTIAL"/>
<setting name="autoMappingUnknownColumnBehavior" value="WARNING"/>
<setting name="defaultExecutorType" value="SIMPLE"/>
<setting name="defaultStatementTimeout" value="25"/>
<setting name="defaultFetchSize" value="100"/>
<setting name="safeRowBoundsEnabled" value="false"/>
<setting name="mapUnderscoreToCamelCase" value="true"/>
<setting name="localCacheScope" value="SESSION"/>
<setting name="jdbcTypeForNull" value="OTHER"/>
<setting name="lazyLoadTriggerMethods" value="equals,clone,hashCode,toString"/>
</settings>
</configuration>
在上面的代码中,我们使用 @ConfigurationProperties(prefix = "spring.datasource.mysql") 将配置文件中的属性绑定到 mysql 的 HikariDataSource 对象上。同样地,我们也为 phoenixDataSource 进行绑定。
这两个数据源分别连接不同的数据库。@Primary注解表示主要的数据源,用于在运行时决定使用哪个数据源。我们创建了一个名为multipleDataSource的方法,该方法添加数据源,并且设置好默认的数据源,
最后,在SqlSessionFactory加载多数据源,以及一些配置文件,这样就可以管理和配置数据库连接。
2.2 项目代码
配置完之后,我们只需要在phoenix接口上配置一下数据源即可,代码如下:
java
public interface TestDetailMapper {
/**
* 保存
* @param testDetail
*/
@DataSource(DataSourceEnum.PHOENIX)
@Insert(" upsert into xxx_xxx (xxxxx) " +
" values (#{xxxx})")
void insert(@Param("xxx") TestDetail testDetail);
/**
* 获取内容
*
* @param xxxx
* @return xxx
*/
@Results(value = {
@Result(property = "xxxx", column = "xxxxx")
})
@DataSource(DataSourceEnum.PHOENIX)
@Select("SELECT XXXX FROM XXX WHERE XXX=#{XXXX}")
TestDetail findByKey(@Param("XXXX") String XXXX);
}
通过上述代码,我们已经成功实现了多数据源的整合。
2.3 注意事项
(1)必须指定主数据源,就是在主数据源的bean注入上加一个@Primary注解,表示同一个类的多个对象注入,优先选择有注解@Primary的对象。
(2)不同数据源的dao和mapper文件最好分开到不同包路径和文件路径下,这样才能单独的配置文件映射,不然会出错。