druid 多数据源详解

发布时间:2023-05-18

Druid 多数据源使用指南

一、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();
}

在每个数据源的配置中加入 initialSizemaxActive 属性,分别设置连接池的初始大小和最大连接数,以避免资源竞争问题。

# 连接池初始大小
spring.datasource.druid.initialSize=5
# 连接池最大活跃数量
spring.datasource.druid.maxActive=20

二、druid 多数据源监控页面

druid 多数据源提供了监控页面,用于查看连接池的状态与连接信息。我们只需要在项目中引入 druid 的监控依赖,并进行相应的配置即可。

<!-- 引入druid的监控依赖 -->
<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>druid-spring-boot-starter</artifactId>
    <version>1.1.20</version>
</dependency>

在项目配置文件中加入监控页面的相关配置。

## 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<String> 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();
        ...
    }
}