本文章与上篇文章对应,在上篇文章的基础上增加数据源,连接池与上篇文章一致
1.HikariCP 多数据源
1.1引入依赖
无需主动引入 HikariCP 的依赖。因为在 Spring Boot 2.X 中,spring-boot-starter-jdbc 默认引入 com.zaxxer.HikariCP 依赖。
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.3.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>lab-19-datasource-pool-hikaricp-single</artifactId>
<dependencies>
<!-- 实现对数据库连接池的自动化配置 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<dependency>
<!-- 本示例,我们使用 MySQL -->
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.48</version>
</dependency>
<!-- 方便写单元测试 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
</project>
1.2应用配置文件
在 application.yml 中,添加 HikariCP 配置,如下:
spring:
# datasource 数据源配置内容
datasource:
# 订单数据源配置
orders:
url: jdbc:mysql://127.0.0.1:3306/test_orders?useSSL=false&useUnicode=true&characterEncoding=UTF-8
driver-class-name: com.mysql.jdbc.Driver
username: root
password:
# HikariCP 自定义配置,对应 HikariConfig 配置属性类
hikari:
minimum-idle: 20 # 池中维护的最小空闲连接数,默认为 10 个。
maximum-pool-size: 20 # 池中最大连接数,包括闲置和使用中的连接,默认为 10 个。
# 用户数据源配置
users:
url: jdbc:mysql://127.0.0.1:3306/test_users?useSSL=false&useUnicode=true&characterEncoding=UTF-8
driver-class-name: com.mysql.jdbc.Driver
username: root
password:
# HikariCP 自定义配置,对应 HikariConfig 配置属性类
hikari:
minimum-idle: 15 # 池中维护的最小空闲连接数,默认为 10 个。
maximum-pool-size: 15 # 池中最大连接数,包括闲置和使用中的连接,默认为 10 个。
我们在 spring.datasource 配置项下,定义了 orders 和 users 两个数据源的配置。而每个数据源的配置,和我们单数据源配置是一致的。
1.3数据源配置类
1.3.1错误示例
在网上,我们会看到这样配置多个数据源的配置类。代码如下:
@Bean(name = "ordersDataSource")
@ConfigurationProperties(prefix = "spring.datasource.orders")
public DataSource ordersDataSource() {
return DataSourceBuilder.create().build();
}
@Bean(name = "usersDataSource")
@ConfigurationProperties(prefix = "spring.datasource.users")
public DataSource ordersDataSource() {
return DataSourceBuilder.create().build();
}
实际上,这样做的话,在部分场景下,会存在问题,这是为什么呢?我们先来理解这段程序的用途。以 #ordersDataSource() 方法为例子:
- DataSourceBuilder.create().build() 代码段,会创建一个 DataSource 数据源。
- 搭配上 @Bean(name = “ordersDataSource”) 注解,会创建一个名字为 “ordersDataSource” 的 DataSource Bean 。这里,我们使用 HikariCP ,所以返回的是 HikariDataSource Bean 。
- @ConfigurationProperties(prefix = “spring.datasource.orders”) 注解,会将 “spring.datasource.orders” 配置项,逐个属性赋值给 DataSource Bean 。
- 看起来貌似没问题,但是如果每个数据源如果有 HikariCP 的 “hikari” 自定义配置项时,它的自定义配置项无法设置到 HikariDataSource Bean 中。因为,“spring.datasource.orders.hikari” 是 “spring.datasource.orders” 的第二层属性。而 HikariDataSource 的配置属性在第一层,这就导致无法正确的设置。
虽然存在该问题,但是大多数项目,我们并不会自定义 HikariCP 的 “hikari” 配置项,所以这个问题就偷偷藏起来,**“不存在”**了。
1.3.2 正确的示例
当然,作为入门的示例,艿艿还是希望提供正确的做法。
在 cn.iocoder.springboot.lab19.datasourcepool.config 包路径下,我们会创建 DataSourceConfig 配置类。代码如下:
// DataSourceConfig.java
@Configuration
public class DataSourceConfig {
/**
* 创建 orders 数据源的配置对象
*/
@Primary
@Bean(name = "ordersDataSourceProperties")
@ConfigurationProperties(prefix = "spring.datasource.orders") // 读取 spring.datasource.orders 配置到 DataSourceProperties 对象
public DataSourceProperties ordersDataSourceProperties() {
return new DataSourceProperties();
}
/**
* 创建 orders 数据源
*/
@Bean(name = "ordersDataSource")
@ConfigurationProperties(prefix = "spring.datasource.orders.hikari") // 读取 spring.datasource.orders 配置到 HikariDataSource 对象
public DataSource ordersDataSource() {
// <1.1> 获得 DataSourceProperties 对象
DataSourceProperties properties = this.ordersDataSourceProperties();
// <1.2> 创建 HikariDataSource 对象
return createHikariDataSource(properties);
}
/**
* 创建 users 数据源的配置对象
*/
@Bean(name = "usersDataSourceProperties")
@ConfigurationProperties(prefix = "spring.datasource.users") // 读取 spring.datasource.users 配置到 DataSourceProperties 对象
public DataSourceProperties usersDataSourceProperties() {
return new DataSourceProperties();
}
/**
* 创建 users 数据源
*/
@Bean(name = "usersDataSource")
@ConfigurationProperties(prefix = "spring.datasource.users.hikari")
public DataSource usersDataSource() {
// 获得 DataSourceProperties 对象
DataSourceProperties properties = this.usersDataSourceProperties();
// 创建 HikariDataSource 对象
return createHikariDataSource(properties);
}
private static HikariDataSource createHikariDataSource(DataSourceProperties properties) {
// 创建 HikariDataSource 对象
HikariDataSource dataSource = properties.initializeDataSourceBuilder().type(HikariDataSource.class).build();
// 设置线程池名
if (StringUtils.hasText(properties.getName())) {
dataSource.setPoolName(properties.getName());
}
return dataSource;
}
}
- 这块代码,我们是参考 Spring Boot DataSourceConfiguration.Hikari 配置类来实现的。
- #ordersDataSourceProperties() 方法,创建 “orders” 数据源的 DataSourceProperties 配置对象。
- @Primary 注解,保证项目中有一个主的 DataSourceProperties Bean 。
- new DataSourceProperties() 代码段,会创建一个 DataSourceProperties 数据源的配置对象。搭配上 @Bean(name = “ordersDataSourceProperties”) 注解,会创建一个名字为 “ordersDataSourceProperties” 的 DataSourceProperties Bean 。
- @ConfigurationProperties(prefix = “spring.datasource.orders”) 注解,会将 “spring.datasource.orders” 配置项,逐个属性赋值给 DataSourceProperties Bean 。
- #ordersDataSource() 方法,创建 orders 数据源。
- <1.1> 处,调用 #ordersDataSourceProperties() 方法,获得 orders 数据源的 DataSourceProperties 。
- <1.2> 处,调用 #createHikariDataSource(DataSourceProperties properties) 方法,创建 HikariDataSource 对象。这样,“spring.datasource.orders” 配置项,逐个属性赋值给 HikariDataSource Bean 。
- 搭配上 @Bean(name = “ordersDataSource”) 注解,会创建一个名字为 “ordersDataSource” 的 HikariDataSource Bean 。
- @ConfigurationProperties(prefix = “spring.datasource.orders.hikari”) 注解,会将 HikariCP 的 “spring.datasource.orders.hikari” 自定义配置项,逐个属性赋值给 HikariDataSource Bean 。
users 数据源的配置,同上,就不重复解释了。
1.4 Application
创建 Application.java 类,配置 @SpringBootApplication 注解即可。代码如下:
// Application.java
@SpringBootApplication
public class Application implements CommandLineRunner {
private Logger logger = LoggerFactory.getLogger(Application.class);
@Resource(name = "ordersDataSource")
private DataSource ordersDataSource;
@Resource(name = "usersDataSource")
private DataSource usersDataSource;
public static void main(String[] args) {
// 启动 Spring Boot 应用
SpringApplication.run(Application.class, args);
}
@Override
public void run(String... args) {
// orders 数据源
try (Connection conn = ordersDataSource.getConnection()) {
// 这里,可以做点什么
logger.info("[run][ordersDataSource 获得连接:{}]", conn);
} catch (SQLException e) {
throw new RuntimeException(e);
}
// users 数据源
try (Connection conn = usersDataSource.getConnection()) {
// 这里,可以做点什么
logger.info("[run][usersDataSource 获得连接:{}]", conn);
} catch (SQLException e) {
throw new RuntimeException(e);
}
}
}
执行日志如下
2022-08-25 15:30:35.060 INFO 45868 --- [ main] com.zaxxer.hikari.HikariDataSource : HikariPool-1 - Starting...
2022-08-25 15:30:35.365 INFO 45868 --- [ main] com.zaxxer.hikari.HikariDataSource : HikariPool-1 - Start completed.
2022-08-25 15:30:35.367 INFO 45868 --- [ main] c.i.s.lab19.datasourcepool.Application : [run][ordersDataSource 获得连接:HikariProxyConnection@1041547629 wrapping com.mysql.jdbc.JDBC4Connection@3c989952]
2022-08-25 15:30:35.371 INFO 45868 --- [ main] com.zaxxer.hikari.HikariDataSource : HikariPool-2 - Starting...
2022-08-25 15:30:35.376 INFO 45868 --- [ main] com.zaxxer.hikari.HikariDataSource : HikariPool-2 - Start completed.
2022-08-25 15:30:35.376 INFO 45868 --- [ main] c.i.s.lab19.datasourcepool.Application : [run][usersDataSource 获得连接:HikariProxyConnection@795748540 wrapping com.mysql.jdbc.JDBC4Connection@7c098bb3]
可以看到两个数据源初始化成功了
2.Druid 多数据源
2.1引入依赖
<dependencies>
<!-- 保证 Spring JDBC 的依赖健全 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<!-- 实现对 Druid 连接池的自动化配置 -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>1.1.21</version>
</dependency>
<dependency> <!-- 本示例,我们使用 MySQL -->
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.48</version>
</dependency>
<!-- 实现对 Spring MVC 的自动化配置,因为我们需要看看 Druid 的监控功能 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- 方便写单元测试 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
2.2应用配置
在 application.yml 中,添加 Druid 配置,如下:
spring:
# datasource 数据源配置内容
datasource:
# 订单数据源配置
orders:
url: jdbc:mysql://127.0.0.1:3306/test_orders?useSSL=false&useUnicode=true&characterEncoding=UTF-8
driver-class-name: com.mysql.jdbc.Driver
username: root
password: 123456
type: com.alibaba.druid.pool.DruidDataSource # 设置类型为 DruidDataSource
# Druid 自定义配置,对应 DruidDataSource 中的 setting 方法的属性
min-idle: 0 # 池中维护的最小空闲连接数,默认为 0 个。
max-active: 20 # 池中最大连接数,包括闲置和使用中的连接,默认为 8 个。
# 用户数据源配置
users:
url: jdbc:mysql://127.0.0.1:3306/test_users?useSSL=false&useUnicode=true&characterEncoding=UTF-8
driver-class-name: com.mysql.jdbc.Driver
username: root
password: 123456
type: com.alibaba.druid.pool.DruidDataSource # 设置类型为 DruidDataSource
# Druid 自定义配置,对应 DruidDataSource 中的 setting 方法的属性
min-idle: 0 # 池中维护的最小空闲连接数,默认为 0 个。
max-active: 20 # 池中最大连接数,包括闲置和使用中的连接,默认为 8 个。
# Druid 自定已配置
druid:
# 过滤器配置
filter:
stat: # 配置 StatFilter ,对应文档 https://github.com/alibaba/druid/wiki/%E9%85%8D%E7%BD%AE_StatFilter
log-slow-sql: true # 开启慢查询记录
slow-sql-millis: 5000 # 慢 SQL 的标准,单位:毫秒
# StatViewServlet 配置
stat-view-servlet: # 配置 StatViewServlet ,对应文档 https://github.com/alibaba/druid/wiki/%E9%85%8D%E7%BD%AE_StatViewServlet%E9%85%8D%E7%BD%AE
enabled: true # 是否开启 StatViewServlet
login-username: admin # 账号
login-password: admin # 密码
2.3数据源配置类
在 cn.iocoder.springboot.lab19.datasourcepool.config 包路径下,我们会创建 DataSourceConfig 配置类。代码如下:
// DataSourceConfig.java
@Configuration
public class DataSourceConfig {
/**
* 创建 orders 数据源
*/
@Primary
@Bean(name = "ordersDataSource")
@ConfigurationProperties(prefix = "spring.datasource.orders") // 读取 spring.datasource.orders 配置到 HikariDataSource 对象
public DataSource ordersDataSource() {
return DruidDataSourceBuilder.create().build();
}
/**
* 创建 users 数据源
*/
@Bean(name = "usersDataSource")
@ConfigurationProperties(prefix = "spring.datasource.users")
public DataSource usersDataSource() {
return DruidDataSourceBuilder.create().build();
}
}
因为我们在 「2.2 应用配置」 中,将 Druid 自定义的配置项,和数据源的通用配置放在了同一级,所以我们只需使用 @ConfigurationProperties(prefix = “spring.datasource.orders”) 这样的方式即可。
当然,「1.3.2 正确的示例」 也是可以这么做的。实际情况下,比较推荐本小节的方式。
2.4 Application
创建 Application.java 类,配置 @SpringBootApplication 注解即可。代码如下:
// Application.java
@SpringBootApplication
public class Application implements CommandLineRunner {
private Logger logger = LoggerFactory.getLogger(Application.class);
@Resource(name = "ordersDataSource")
private DataSource ordersDataSource;
@Resource(name = "usersDataSource")
private DataSource usersDataSource;
public static void main(String[] args) {
// 启动 Spring Boot 应用
SpringApplication.run(Application.class, args);
}
@Override
public void run(String... args) {
// orders 数据源
logger.info("[run][获得数据源:{}]", ordersDataSource.getClass());
// users 数据源
logger.info("[run][获得数据源:{}]", usersDataSource.getClass());
}
}
执行日志如下:
2022-08-25 21:39:24.063 INFO 49670 --- [ main] c.i.s.lab19.datasourcepool.Application : [run][获得数据源:class com.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceWrapper]
2022-08-25 21:39:24.064 INFO 49670 --- [ main] c.i.s.lab19.datasourcepool.Application : [run][获得数据源:class com.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceWrapper]
可以看到,两个 DruidDataSource 成功初始化。
2.5监控功能
与单数据源一样,不过这个可以看到两个数据源
摘要: 原创出处[芋道源码]
Q.E.D.