Skip to content

DS数据源使用指南:同一套服务使用不同数据库

概述

DS(DataSource)数据源是现代应用程序中管理数据库连接的核心组件。在微服务架构和多环境部署中,同一套服务代码需要连接不同的数据库实例,这时DS的灵活配置就显得尤为重要。

什么是DS数据源

DS数据源是一个抽象层,它封装了数据库连接的详细信息,包括:

  • 数据库URL
  • 用户名和密码
  • 连接池配置
  • 事务管理
  • 连接超时设置

核心优势

1. 环境隔离

  • 开发环境:连接本地开发数据库
  • 测试环境:连接测试数据库
  • 生产环境:连接生产数据库

2. 配置灵活性

  • 通过配置文件动态切换数据库
  • 支持多种数据库类型(MySQL、PostgreSQL、Oracle等)
  • 无需修改代码即可切换数据源

3. 连接池管理

  • 自动管理数据库连接
  • 提高应用性能
  • 防止连接泄漏

实现方案

方案一:配置文件驱动

application.yml配置示例

yaml
spring:
  profiles:
    active: dev

---
spring:
  profiles: dev
  datasource:
    url: jdbc:mysql://localhost:3306/dev_db
    username: dev_user
    password: dev_password
    driver-class-name: com.mysql.cj.jdbc.Driver

---
spring:
  profiles: test
  datasource:
    url: jdbc:mysql://test-server:3306/test_db
    username: test_user
    password: test_password
    driver-class-name: com.mysql.cj.jdbc.Driver

---
spring:
  profiles: prod
  datasource:
    url: jdbc:mysql://prod-server:3306/prod_db
    username: prod_user
    password: prod_password
    driver-class-name: com.mysql.cj.jdbc.Driver

Java配置类

java
@Configuration
public class DataSourceConfig {
    
    @Bean
    @ConfigurationProperties(prefix = "spring.datasource")
    public DataSource dataSource() {
        return DataSourceBuilder.create().build();
    }
    
    @Bean
    public JdbcTemplate jdbcTemplate(DataSource dataSource) {
        return new JdbcTemplate(dataSource);
    }
}

方案二:多数据源配置

配置多个数据源

yaml
spring:
  datasource:
    primary:
      url: jdbc:mysql://localhost:3306/primary_db
      username: primary_user
      password: primary_password
      driver-class-name: com.mysql.cj.jdbc.Driver
    secondary:
      url: jdbc:postgresql://localhost:5432/secondary_db
      username: secondary_user
      password: secondary_password
      driver-class-name: org.postgresql.Driver

Java多数据源配置

java
@Configuration
public class MultiDataSourceConfig {
    
    @Primary
    @Bean(name = "primaryDataSource")
    @ConfigurationProperties(prefix = "spring.datasource.primary")
    public DataSource primaryDataSource() {
        return DataSourceBuilder.create().build();
    }
    
    @Bean(name = "secondaryDataSource")
    @ConfigurationProperties(prefix = "spring.datasource.secondary")
    public DataSource secondaryDataSource() {
        return DataSourceBuilder.create().build();
    }
    
    @Bean(name = "primaryJdbcTemplate")
    public JdbcTemplate primaryJdbcTemplate(@Qualifier("primaryDataSource") DataSource dataSource) {
        return new JdbcTemplate(dataSource);
    }
    
    @Bean(name = "secondaryJdbcTemplate")
    public JdbcTemplate secondaryJdbcTemplate(@Qualifier("secondaryDataSource") DataSource dataSource) {
        return new JdbcTemplate(dataSource);
    }
}

方案三:动态数据源切换

自定义数据源路由

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

public class DataSourceContextHolder {
    private static final ThreadLocal<String> contextHolder = new ThreadLocal<>();
    
    public static void setDataSourceType(String dataSourceType) {
        contextHolder.set(dataSourceType);
    }
    
    public static String getDataSourceType() {
        return contextHolder.get();
    }
    
    public static void clearDataSourceType() {
        contextHolder.remove();
    }
}

注解驱动的数据源切换

java
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface DataSource {
    String value() default "primary";
}

@Aspect
@Component
public class DataSourceAspect {
    
    @Around("@annotation(dataSource)")
    public Object around(ProceedingJoinPoint point, DataSource dataSource) throws Throwable {
        String dsKey = dataSource.value();
        DataSourceContextHolder.setDataSourceType(dsKey);
        try {
            return point.proceed();
        } finally {
            DataSourceContextHolder.clearDataSourceType();
        }
    }
}

使用示例

服务层使用

java
@Service
public class UserService {
    
    @Autowired
    @Qualifier("primaryJdbcTemplate")
    private JdbcTemplate primaryJdbcTemplate;
    
    @Autowired
    @Qualifier("secondaryJdbcTemplate")
    private JdbcTemplate secondaryJdbcTemplate;
    
    // 使用主数据源
    public List<User> getUsersFromPrimary() {
        return primaryJdbcTemplate.query(
            "SELECT * FROM users", 
            new BeanPropertyRowMapper<>(User.class)
        );
    }
    
    // 使用辅助数据源
    @DataSource("secondary")
    public List<User> getUsersFromSecondary() {
        return secondaryJdbcTemplate.query(
            "SELECT * FROM users", 
            new BeanPropertyRowMapper<>(User.class)
        );
    }
}

最佳实践

1. 环境变量配置

bash
# 设置环境变量
export SPRING_PROFILES_ACTIVE=prod
export DB_URL=jdbc:mysql://prod-server:3306/prod_db
export DB_USERNAME=prod_user
export DB_PASSWORD=prod_password

2. 配置加密

yaml
spring:
  datasource:
    url: jdbc:mysql://localhost:3306/mydb
    username: ${DB_USERNAME:defaultuser}
    password: ${DB_PASSWORD:defaultpass}

3. 连接池优化

yaml
spring:
  datasource:
    hikari:
      maximum-pool-size: 20
      minimum-idle: 5
      connection-timeout: 30000
      idle-timeout: 600000
      max-lifetime: 1800000

4. 健康检查

java
@Component
public class DataSourceHealthIndicator implements HealthIndicator {
    
    @Autowired
    private DataSource dataSource;
    
    @Override
    public Health health() {
        try (Connection connection = dataSource.getConnection()) {
            if (connection.isValid(1)) {
                return Health.up()
                    .withDetail("database", "Available")
                    .build();
            }
        } catch (Exception e) {
            return Health.down()
                .withDetail("database", "Unavailable")
                .withException(e)
                .build();
        }
        return Health.down().build();
    }
}

常见问题与解决方案

1. 连接池耗尽

问题:应用程序出现连接超时错误 解决方案

  • 检查连接是否正确关闭
  • 调整连接池大小
  • 设置合适的连接超时时间

2. 事务管理

问题:多数据源环境下事务不一致 解决方案

  • 使用分布式事务管理器
  • 避免跨数据源事务
  • 实现补偿机制

3. 性能优化

问题:数据库连接性能差 解决方案

  • 启用连接池
  • 优化SQL查询
  • 使用读写分离

总结

DS数据源的灵活配置是现代应用程序的重要特性。通过合理的配置和设计,我们可以:

  1. 实现环境隔离:不同环境使用不同数据库
  2. 提高系统灵活性:无需修改代码即可切换数据源
  3. 优化性能:通过连接池和配置优化提升性能
  4. 增强可维护性:清晰的配置结构便于维护

选择合适的数据源配置方案,结合项目实际需求,可以构建出高效、稳定、可扩展的数据访问层。

Released under the MIT License.