使用 Spring Boot,可以动态添加切换数据源,需要用到Spring JDBC模块中的 AbstractRoutingDataSource 类和 DynamicDataSourceHolder 维护一个存储当前使用的数据源 key 的 ThreadLocal 对象。步骤如下:
导入依赖
首先,在 pom.xml 中导入 Spring Boot 和 Spring JDBC 的依赖。
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
定义数据源
其次,在 application.yml 中定义数据源。
spring:
datasource:
default:
driver-class-name: com.mysql.jdbc.Driver
url: jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=UTF-8
username: root
password: root
db1:
driver-class-name: com.mysql.jdbc.Driver
url: jdbc:mysql://localhost:3306/db1?useUnicode=true&characterEncoding=UTF-8
username: root
password: root
db2:
driver-class-name: com.mysql.jdbc.Driver
url: jdbc:mysql://localhost:3306/db2?useUnicode=true&characterEncoding=UTF-8
username: root
password: root
定义动态数据源
public class DynamicDataSource extends AbstractRoutingDataSource {
@Override
protected Object determineCurrentLookupKey() {
return DynamicDataSourceHolder.getDataSourceKey();
}
}
维护当前使用数据源的 key
public class DynamicDataSourceHolder {
private static final ThreadLocal<String> dataSourceKey = new InheritableThreadLocal<>();
public static void setDataSourceKey(String key) {
dataSourceKey.set(key);
}
public static String getDataSourceKey() {
return dataSourceKey.get();
}
public static void clearDataSourceKey() {
dataSourceKey.remove();
}
}
配置动态数据源
@Configuration
public class DataSourceConfig {
@Bean
@ConfigurationProperties("spring.datasource")
public DataSource defaultDataSource() {
return DataSourceBuilder.create().build();
}
@Bean
@ConfigurationProperties("spring.datasource.db1")
public DataSource db1DataSource() {
return DataSourceBuilder.create().build();
}
@Bean
@ConfigurationProperties("spring.datasource.db2")
public DataSource db2DataSource() {
return DataSourceBuilder.create().build();
}
@Bean
public DynamicDataSource dynamicDataSource() {
Map<Object, Object> targetDataSources = new HashMap<>();
targetDataSources.put("default", defaultDataSource());
targetDataSources.put("db1", db1DataSource());
targetDataSources.put("db2", db2DataSource());
DynamicDataSource dynamicDataSource = new DynamicDataSource();
dynamicDataSource.setTargetDataSources(targetDataSources);
dynamicDataSource.setDefaultTargetDataSource(defaultDataSource());
return dynamicDataSource;
}
@Bean
public SqlSessionFactoryBean sqlSessionFactory(DynamicDataSource dynamicDataSource) throws Exception {
SqlSessionFactoryBean sqlSessionFactory = new SqlSessionFactoryBean();
sqlSessionFactory.setDataSource(dynamicDataSource);
return sqlSessionFactory;
}
}
上述代码中,@ConfigurationProperties("spring.datasource") 表示读取 yml 配置文件中的 spring.datasource 参数,这里将 default 数据源的信息读入 DataSource 中,其他两个数据源同理。DynamicDataSource 类是继承了 Spring JDBC 中的 AbstractRoutingDataSource 类,它会调用 DynamicDataSourceHolder 中的 getDataSourceKey() 方法获取当前数据源 key,然后根据这个 key 从 targetDataSources 中取出对应的数据源。
测试
为了方便测试,我们添加 Controller 和 Service。
@RestController
@RequestMapping("/user")
public class UserController {
@Autowired
private UserService userService;
@GetMapping("/{id}")
public User findById(@PathVariable Integer id, @RequestParam String db) {
DynamicDataSourceHolder.setDataSourceKey(db);
User user = userService.findById(id);
DynamicDataSourceHolder.clearDataSourceKey();
return user;
}
}
@Service
public class UserService {
@Autowired
private UserMapper userMapper;
public User findById(Integer id) {
return userMapper.findById(id);
}
}
@Mapper
public interface UserMapper {
User findById(Integer id);
}
这个示例中,我们为 Controller 增加了一个请求参数 db,它的值可以是 default、db1 或 db2,为了测试是否切换了数据源,我们在 findById() 方法中调用 DynamicDataSourceHolder.setDataSourceKey() 方法设置数据源 key,然后在调用 UserService.findById() 方法完成查询后,调用 DynamicDataSourceHolder.clearDataSourceKey() 方法清除数据源 key,这样就完成了数据源的切换。
$ curl http://localhost:8080/user/1?db=db1
{"id":1,"name":"User 1","age":20}
$ curl http://localhost:8080/user/2?db=db2
{"id":2,"name":"User 2","age":30}
根据访问地址中的 db 参数的值,会分别从 db1 和 db2 数据库中查询数据。
可以看到,使用 Spring Boot 实现动态添加切换数据源非常简单。
本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:springboot+dynamicDataSource动态添加切换数据源方式 - Python技术站