Spring Boot 中动态数据源配置与使用详解
在现代应用中,处理多数据源是常见的需求。可能由于业务需要,或者为了实现读写分离,我们往往需要在同一个应用中配置多个数据源,并根据具体的操作选择不同的数据源。在 Spring Boot 中,这样的需求可以通过动态数据源来轻松实现。本篇博客将详细介绍如何在 Spring Boot 中配置和使用动态数据源,并演示如何切换到指定的数据源。
一、为什么要使用动态数据源?
-
业务隔离:在一些复杂的业务场景中,不同的模块可能需要连接不同的数据库。通过动态数据源配置,可以在同一个应用中隔离这些不同的数据库访问。
-
读写分离:为了提升系统的性能,通常会将读写操作分离到不同的数据库上。比如,将写操作放在主数据库,而读操作放在从数据库上。
-
数据库迁移:在系统迁移期间,可能需要在两个数据库之间切换,从而确保迁移的平稳进行。
二、Spring Boot 中的多数据源配置
我们将通过一个示例来介绍如何在 Spring Boot 中配置和使用动态数据源。假设我们有两个数据源,一个是 master
,另一个是 adcontrol
。master
数据源主要用于主业务数据库,而 adcontrol
数据源用于广告控制的相关数据存储。
1. 数据源配置
首先,我们需要在 application.yml
文件中配置两个数据源。
yaml
datasource:
dynamic:
primary: master # 默认使用master库
strict: false # 不使用严格模式
datasource:
master:
url: jdbc:mysql://127.0.0.1:3306/test?serverTimezone=Asia/Shanghai&characterEncoding=utf8&useSSL=false
username: root
password: 123456
driver-class-name: com.mysql.cj.jdbc.Driver
hikari:
connection-timeout: 30000
max-lifetime: 1800000
max-pool-size: 15
min-idle: 5
connection-test-query: select 1
pool-name: YsxHikariCP
adcontrol:
url: jdbc:mysql://ip:3306/test2?serverTimezone=Asia/Shanghai&characterEncoding=utf8&useSSL=false
username: test
password: test
driver-class-name: com.mysql.cj.jdbc.Driver
上述配置中,master
数据源是默认使用的数据源,而 adcontrol
数据源是备用的广告控制数据源。
2. 引入动态数据源依赖
为了让 Spring Boot 能够识别和使用这些动态数据源,我们需要引入动态数据源的依赖库。这里我们使用 dynamic-datasource-spring-boot-starter
这个开源库。
在 pom.xml
中添加如下依赖:
xml
<dependency>
<groupId>com.github.dynamic-datasource</groupId>
<artifactId>dynamic-datasource-spring-boot-starter</artifactId>
<version>3.2.1</version> <!-- 确保使用合适的版本 -->
</dependency>
3. 配置动态数据源
通过 DynamicDataSource
,我们可以在应用中灵活切换数据源。下面是一个简单的 DynamicDataSource
配置示例:
java
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import com.github.dynamic.datasource.DynamicRoutingDataSource;
import javax.sql.DataSource;
import org.springframework.boot.autoconfigure.jdbc.DataSourceBuilder;
import java.util.HashMap;
import java.util.Map;
@Configuration
public class DataSourceConfig {
@Bean
public DataSource dataSource() {
DynamicRoutingDataSource dataSource = new DynamicRoutingDataSource();
// 配置主数据源
DataSource masterDataSource = DataSourceBuilder.create()
.url("jdbc:mysql://127.0.0.1:3306/test1?serverTimezone=Asia/Shanghai&characterEncoding=utf8&useSSL=false")
.username("root")
.password("123456")
.driverClassName("com.mysql.cj.jdbc.Driver")
.build();
// 配置广告控制数据源
DataSource adcontrolDataSource = DataSourceBuilder.create()
.url("jdbc:mysql://ip1:3306/test2?serverTimezone=Asia/Shanghai&characterEncoding=utf8&useSSL=false")
.username("test")
.password("test")
.driverClassName("com.mysql.cj.jdbc.Driver")
.build();
// 将数据源放入Map
Map<Object, Object> dataSourceMap = new HashMap<>();
dataSourceMap.put("master", masterDataSource);
dataSourceMap.put("adcontrol", adcontrolDataSource);
dataSource.setDefaultTargetDataSource(masterDataSource);
dataSource.setTargetDataSources(dataSourceMap);
return dataSource;
}
}
4. 使用 @DS
注解动态切换数据源
在服务层,我们可以通过 @DS
注解来指定当前方法应该使用哪个数据源。例如:
java
import com.github.dynamic.datasource.annotation.DS;
import org.springframework.stereotype.Service;
@Service
public class MyService {
@DS("adcontrol")
public void handleAdControlLogic() {
// 使用adcontrol数据源执行操作
}
@DS("master")
public void handleMasterLogic() {
// 使用master数据源执行操作
}
}
通过 @DS
注解,我们可以在方法层面灵活切换数据源,确保不同的业务逻辑使用正确的数据库连接。
三、异常处理与回滚
在使用多个数据源时,处理好事务和异常非常重要。如果在一个事务内执行了多个数据源的操作,那么事务的管理和异常处理就变得尤为关键。
Spring 提供了全局事务管理器的支持,可以配置为管理多个数据源的事务。但是在使用 dynamic-datasource
时,要特别注意确保在同一个事务中操作的多个数据源能够正确地提交或回滚。
例如:
java
import org.springframework.transaction.annotation.Transactional;
@Service
public class MyService {
@Transactional
@DS("master")
public void processTransaction() {
try {
// 操作master数据库
handleMasterLogic();
// 切换到adcontrol数据源
handleAdControlLogic();
} catch (Exception e) {
// 处理异常,可能需要回滚事务
throw new RuntimeException("事务失败,进行回滚", e);
}
}
@DS("adcontrol")
public void handleAdControlLogic() {
// 操作adcontrol数据库
}
@DS("master")
public void handleMasterLogic() {
// 操作master数据库
}
}
在上面的代码中,如果 handleAdControlLogic
方法抛出了异常,那么整个事务将被回滚。
四、常见问题与解决方案
-
数据源切换失败
- 确保
@DS
注解指向的名称与配置中的数据源名称完全一致。 - 检查
DynamicDataSource
是否正确配置。
- 确保
-
事务回滚失败
- 确保在同一个事务中使用的所有数据源都支持事务管理。
- 使用
@Transactional
注解来管理事务。
-
性能问题
- 动态数据源切换可能会带来额外的性能开销。可以考虑使用连接池优化数据库连接管理。
-
无法连接数据库
- 检查数据库连接配置,确保
url
、username
和password
等参数正确。 - 检查数据库服务器是否可达。
- 检查数据库连接配置,确保
五、总结
通过动态数据源配置,Spring Boot 应用可以轻松应对多数据源的复杂需求。无论是业务隔离、读写分离,还是数据库迁移,动态数据源都能够提供灵活且高效的解决方案。
在实际应用中,合理规划和使用多数据源,可以显著提升系统的可扩展性和可靠性。在实现过程中,需要特别注意事务管理和异常处理,以确保数据的一致性和完整性。
通过本文的介绍,相信你已经掌握了在 Spring Boot 中配置和使用动态数据源的基本方法。在实际项目中,可以根据业务需求,进一步优化和扩展动态数据源的使用。希望本文能对你有所帮助。