一、druid 多数据源卡顿
在使用 druid 多数据源的过程中,有时候我们会遇到卡顿的情况。这主要是因为多个数据源使用同一连接池,这会导致连接池资源的竞争。因此,为了解决这个问题,我们可以考虑对每个数据源都单独建立一个连接池。
@Bean(name = "ds1")
@ConfigurationProperties(prefix = "spring.datasource.ds1")
public DataSource ds1() {
return DruidDataSourceBuilder.create().build();
}
@Bean(name = "ds2")
@ConfigurationProperties(prefix = "spring.datasource.ds2")
public DataSource ds2() {
return DruidDataSourceBuilder.create().build();
}
在每个数据源的配置中加入 initialSize
和 maxActive
属性,分别设置连接池的初始大小和最大连接数,以避免资源竞争问题。
# 连接池初始大小
spring.datasource.druid.initialSize=5
# 连接池最大活跃数量
spring.datasource.druid.maxActive=20
二、druid 多数据源监控页面
druid 多数据源提供了监控页面,用于查看连接池的状态与连接信息。我们只需要在项目中引入 druid 的监控依赖,并进行相应的配置即可。
com.alibaba
druid-spring-boot-starter
1.1.20
在项目配置文件中加入监控页面的相关配置。
## druid的相关部分
# 激活监控功能,允许访问druid监控页面
spring.datasource.druid.stat-view-servlet.enabled=true
# 配置druid监控页面的访问路径
spring.datasource.druid.stat-view-servlet.url-pattern=/druid/*
# 监控用户的账号密码,不设置则可输入任意账号密码进入监控页面
spring.datasource.druid.stat-view-servlet.login-username=admin
spring.datasource.druid.stat-view-servlet.login-password=admin
三、druid 多数据源配置
在使用 druid 多数据源的过程中,我们需要在项目中配置多个数据源。这里我们给出一个简单的配置示例。
## 数据库1的相关配置
spring.datasource.ds1.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.ds1.url=jdbc:mysql://localhost:3306/test1
spring.datasource.ds1.username=root
spring.datasource.ds1.password=123456
## 数据库2的相关配置
spring.datasource.ds2.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.ds2.url=jdbc:mysql://localhost:3306/test2
spring.datasource.ds2.username=root
spring.datasource.ds2.password=123456
四、druid 多数据源切换
在使用 druid 多数据源时,我们需要切换数据源。这里我们介绍两种切换数据源的方法。
方法一:利用 @Qualifier
注解指定数据源名称,实现数据源的动态切换。
@Autowired
private ApplicationContext context;
// 切换数据源,指定数据源名称
public void changeDataSource(String dataSourceName) {
DataSource dataSource = (DataSource) context.getBean(dataSourceName);
DynamicDataSourceContextHolder.setDataSource(dynamicDataSource);
}
方法二:使用多线程与 ThreadLocal 实现数据源的动态切换。
static class DynamicDataSource extends AbstractRoutingDataSource {
@Override
protected Object determineCurrentLookupKey() {
return DynamicDataSourceContextHolder.getDataSource();
}
}
public class DynamicDataSourceContextHolder {
private static final ThreadLocal
contextHolder = new ThreadLocal<>();
public static void setDataSource(String dataSourceName) {
contextHolder.set(dataSourceName);
}
public static String getDataSource() {
return contextHolder.get();
}
public static void clearDataSource() {
contextHolder.remove();
}
}
五、druid 多数据源监控
druid 多数据源提供了多种监控指标,包括连接数、并发请求数、SQL 运行时间、错误数等。
## 配置druid监控统计功能
# 数据源监控开关
spring.datasource.druid.stat.enable=true
# 配置druid监控统计持续的时间
spring.datasource.druid.stat.time-between-log-stats-millis=60000
# 慢SQL查询阈值
spring.datasource.druid.filter.slowsql.enabled=true
spring.datasource.druid.filter.slowsql.time-threshold=1000
# 启用mergeSql功能
spring.datasource.druid.filter.stat.merge-sql=true
# SQL合并的阈值
spring.datasource.druid.filter.stat.slow-sql-millis=1000
六、druid 数据源配置
除了多数据源方案,我们还可以对单个数据源进行配置。可以配置以下选项:初始大小、最大连接数、最小连接数、获取连接的最大等待时间、回收连接的最大等待时间、是否进行前缀截断、是否缓存 Statement、是否允许进行多条 SQL 合并等。
## 数据源的相关配置
spring.datasource.initialSize=5 # 初始化连接数量
spring.datasource.maxActive=10 # 最大连接数量
spring.datasource.minIdle=2 # 最小空闲连接数量
spring.datasource.maxWait=60000 # 获取连接的最大等待时间,单位毫秒
spring.datasource.timeBetweenEvictionRunsMillis=60000 # 连接回收的时间间隔,单位毫秒
spring.datasource.minEvictableIdleTimeMillis=300000 # 连接可被回收的最大空闲时间,单位毫秒
spring.datasource.testWhileIdle=true # 测试连接是否有效
spring.datasource.validationQuery=SELECT 1 FROM DUAL # 验证 SQL 语句
spring.datasource.testOnBorrow=false # 是否在从池中取出连接前进行检验
spring.datasource.testOnReturn=false # 是否在归还到池中前进行检验
spring.datasource.poolPreparedStatements=true # 是否缓存 Statement 对象
spring.datasource.maxPoolPreparedStatementPerConnectionSize=20 # 开启缓存后,每个连接允许缓存的 Statement 对象数量
# 开启对多条 SQL 语句合并批量更新操作的支持,例如 insertBatch,updateBatch 等
spring.datasource.connectionProperties=druid.stat.mergeSql=true;druid.stat.slowSqlMillis=5000
七、druid 多数据源事务
在使用 druid 多数据源时,需要对事务进行特别的处理。我们需要使用 Spring 的 @Transactional
注解,在方法级别上进行事务的注解。同时,我们还需要在每个数据源上绑定单独的事务管理器。
@Bean(name = "transactionManager1")
public DataSourceTransactionManager transactionManager1() {
return new DataSourceTransactionManager(ds1());
}
@Bean(name = "transactionManager2")
public DataSourceTransactionManager transactionManager2() {
return new DataSourceTransactionManager(ds2());
}
之后,在需要使用事务的方法上加入 @Transactional
注解,并指定数据源名称。
@Transactional(value = "transactionManager1")
public void saveUser(User user) {
userDao.insert(user);
}
@Transactional(value = "transactionManager2")
public void saveOrder(Order order) {
orderDao.insert(order);
}
八、druid 多数据源连接超时
在使用 druid 多数据源时,我们可能会遇到连接超时的问题。我们可以通过设置超时时间来解决这个问题。
spring.datasource.druid.time-between-eviction-runs-millis=60000 # 连接回收的时间间隔,单位毫秒
spring.datasource.druid.min-evictable-idle-time-millis=300000 # 连接可被回收的最大空闲时间,单位毫秒
spring.datasource.druid.max-evictable-idle-time-millis=1800000 # 连接池中连接的最大超时时间,单位毫秒
九、druid 多数据源创建及使用
在使用 druid 多数据源时,我们需要先创建多个数据源,之后再根据实际情况使用相应的数据源。
@Configuration
public class DataSourceConfig {
@Bean(name = "ds1")
@ConfigurationProperties(prefix = "spring.datasource.ds1")
public DataSource ds1() {
return DruidDataSourceBuilder.create().build();
}
@Bean(name = "ds2")
@ConfigurationProperties(prefix = "spring.datasource.ds2")
public DataSource ds2() {
return DruidDataSourceBuilder.create().build();
}
}
@Component
public class DataSourceUtil {
// 注入所有数据源
@Autowired
@Qualifier("ds1")
private DataSource ds1;
@Autowired
@Qualifier("ds2")
private DataSource ds2;
public void execute() {
// 使用ds1数据源
Connection conn = ds1.getConnection();
...
// 使用ds2数据源
conn = ds2.getConnection();
...
}
}