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.DriverJava配置类
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.DriverJava多数据源配置
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_password2. 配置加密
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: 18000004. 健康检查
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数据源的灵活配置是现代应用程序的重要特性。通过合理的配置和设计,我们可以:
- 实现环境隔离:不同环境使用不同数据库
- 提高系统灵活性:无需修改代码即可切换数据源
- 优化性能:通过连接池和配置优化提升性能
- 增强可维护性:清晰的配置结构便于维护
选择合适的数据源配置方案,结合项目实际需求,可以构建出高效、稳定、可扩展的数据访问层。