1. 引入 Druid 后是否需要自己维护连接池?

1.1 Druid 的作用

  • Druid 是一个高性能的数据库连接池组件,它负责管理数据库连接的生命周期。
  • 一旦配置好 Druid 数据源,所有的连接获取和释放都会由 Druid 自动处理。
  • 只需要在配置文件中定义数据源的相关参数(如最大连接数、最小空闲连接数等),Druid 会根据这些参数动态管理连接池。

1.2 不需要手动维护连接池

  • 在使用 JdbcTemplate 或其他数据库操作工具时,Druid 会自动从连接池中获取连接,并在操作完成后将连接返回到池中。
  • 因此,不需要手动创建或关闭数据库连接,所有这些工作都由 Druid 完成。

2. 涉及多种数据源时的处理方式

当项目中需要支持多个数据源(如 MySQL、Oracle、GBase 等)时,Spring Boot 提供了灵活的机制来实现多数据源的支持。以下是具体的解决方案:

2.1 配置多个数据源

在 Spring Boot 中,可以通过以下步骤配置多个数据源:

(1) 定义多个数据源 Bean

为每个数据源创建一个独立的 DataSource Bean,并指定对应的连接池配置。

java
@Configuration
public class DataSourceConfig {

    @Bean(name = "mysqlDataSource")
    @ConfigurationProperties(prefix = "spring.datasource.mysql")
    public DataSource mysqlDataSource() {
        return DruidDataSourceBuilder.create().build();
    }

    @Bean(name = "oracleDataSource")
    @ConfigurationProperties(prefix = "spring.datasource.oracle")
    public DataSource oracleDataSource() {
        return DruidDataSourceBuilder.create().build();
    }

    @Bean(name = "gbaseDataSource")
    @ConfigurationProperties(prefix = "spring.datasource.gbase")
    public DataSource gbaseDataSource() {
        return DruidDataSourceBuilder.create().build();
    }
}

(2) 配置文件中定义多数据源参数

application.ymlapplication.properties 中,分别为每个数据源定义配置。

yaml
spring:
  datasource:
    mysql:
      url: jdbc:mysql://localhost:3306/mysql_db
      username: root
      password: 123456
      driver-class-name: com.mysql.cj.jdbc.Driver
    oracle:
      url: jdbc:oracle:thin:@localhost:1521:orcl
      username: scott
      password: tiger
      driver-class-name: oracle.jdbc.OracleDriver
    gbase:
      url: jdbc:gbase://localhost:5258/gbase_db
      username: admin
      password: gbase123
      driver-class-name: com.gbase.jdbc.Driver

2.2 为每个数据源配置 JdbcTemplate

为了区分不同数据源的操作,可以为每个数据源创建独立的 JdbcTemplate 实例。

java
@Configuration
public class JdbcTemplateConfig {

    @Bean(name = "mysqlJdbcTemplate")
    public JdbcTemplate mysqlJdbcTemplate(@Qualifier("mysqlDataSource") DataSource dataSource) {
        return new JdbcTemplate(dataSource);
    }

    @Bean(name = "oracleJdbcTemplate")
    public JdbcTemplate oracleJdbcTemplate(@Qualifier("oracleDataSource") DataSource dataSource) {
        return new JdbcTemplate(dataSource);
    }

    @Bean(name = "gbaseJdbcTemplate")
    public JdbcTemplate gbaseJdbcTemplate(@Qualifier("gbaseDataSource") DataSource dataSource) {
        return new JdbcTemplate(dataSource);
    }
}

2.3 使用多数据源

在业务代码中,通过注入对应的 JdbcTemplate 来操作不同的数据源。

java
@Service
public class MultiDataSourceService {

    @Autowired
    @Qualifier("mysqlJdbcTemplate")
    private JdbcTemplate mysqlJdbcTemplate;

    @Autowired
    @Qualifier("oracleJdbcTemplate")
    private JdbcTemplate oracleJdbcTemplate;

    @Autowired
    @Qualifier("gbaseJdbcTemplate")
    private JdbcTemplate gbaseJdbcTemplate;

    public void queryFromMysql() {
        List<Map<String, Object>> result = mysqlJdbcTemplate.queryForList("SELECT * FROM users");
        System.out.println("MySQL Result: " + result);
    }

    public void queryFromOracle() {
        List<Map<String, Object>> result = oracleJdbcTemplate.queryForList("SELECT * FROM employees");
        System.out.println("Oracle Result: " + result);
    }

    public void queryFromGbase() {
        List<Map<String, Object>> result = gbaseJdbcTemplate.queryForList("SELECT * FROM customers");
        System.out.println("GBase Result: " + result);
    }
}

2.4 动态切换数据源(可选)

如果需要在运行时动态切换数据源,可以使用 Spring 提供的 AbstractRoutingDataSource 来实现动态数据源路由。

(1) 定义动态数据源

java
public class DynamicDataSource extends AbstractRoutingDataSource {
    @Override
    protected Object determineCurrentLookupKey() {
        return DataSourceContextHolder.getDataSource();
    }
}

(2) 数据源上下文管理

java
public class DataSourceContextHolder {
    private static final ThreadLocal<String> contextHolder = new ThreadLocal<>();

    public static void setDataSource(String dataSource) {
        contextHolder.set(dataSource);
    }

    public static String getDataSource() {
        return contextHolder.get();
    }

    public static void clearDataSource() {
        contextHolder.remove();
    }
}

(3) 配置动态数据源

java
@Configuration
public class DynamicDataSourceConfig {

    @Bean
    public DataSource dynamicDataSource(
            @Qualifier("mysqlDataSource") DataSource mysqlDataSource,
            @Qualifier("oracleDataSource") DataSource oracleDataSource,
            @Qualifier("gbaseDataSource") DataSource gbaseDataSource) {

        Map<Object, Object> targetDataSources = new HashMap<>();
        targetDataSources.put("mysql", mysqlDataSource);
        targetDataSources.put("oracle", oracleDataSource);
        targetDataSources.put("gbase", gbaseDataSource);

        DynamicDataSource dynamicDataSource = new DynamicDataSource();
        dynamicDataSource.setDefaultTargetDataSource(mysqlDataSource); // 默认数据源
        dynamicDataSource.setTargetDataSources(targetDataSources);
        return dynamicDataSource;
    }
}

(4) 使用动态数据源

java
@Service
public class DynamicService {

    @Autowired
    private JdbcTemplate jdbcTemplate;

    public void queryWithDynamicDataSource(String dataSourceKey) {
        DataSourceContextHolder.setDataSource(dataSourceKey);
        try {
            List<Map<String, Object>> result = jdbcTemplate.queryForList("SELECT * FROM some_table");
            System.out.println("Result: " + result);
        } finally {
            DataSourceContextHolder.clearDataSource();
        }
    }
}

3、何时创建连接?

场景是否创建连接说明
Druid 初始化时取决于initialSize参数如果initialSize > 0,初始化时会创建指定数量的连接;否则不创建。
第一次触发查询时按需创建如果连接池中没有可用连接,Druid 会动态创建新的连接。
连接池空闲连接不足时动态补充如果空闲连接数小于minIdle,Druid 会自动补充连接,直到达到minIdle