添加依赖
implementation group: 'com.alibaba', name: 'druid-spring-boot-starter', version: '1.2.8'
implementation group: 'org.mybatis.spring.boot', name: 'mybatis-spring-boot-starter', version: '2.1.3'
runtimeOnly 'mysql:mysql-connector-java'
配置数据源
server:
port: 8080
spring:
thymeleaf:
cache: false
mybatis:
mapper-locations: classpath:/mapper/*.xml
type-aliases-package: com.zx.SpringBootDemo.entity
configuration:
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
map-underscore-to-camel-case: true
# 数据源
datasource:
base:
name: default
url: jdbc:mysql://127.0.0.1:3306/test?useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai
username: root
password: 123456
driverClassName: com.mysql.jdbc.Driver
list:
- name: a
url: jdbc:mysql://127.0.0.1:3306/test?useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai
username: root
password: 123456
driverClassName: com.mysql.jdbc.Driver
- name: b
url: jdbc:mysql://127.0.0.1:3306/test2?useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai
username: root
password: 123456
driverClassName: com.mysql.jdbc.Driver
配置实体类
public class DataSourcePropertyDetail {
/**
*
*/
private String name;
/**
* 数据库地址
*/
private String url;
/**
* 用户名
*/
private String username;
/**
* 密码
*/
private String password;
/**
*
*/
private String driverClassName;
}
@Component
@ConfigurationProperties(prefix = "datasource")
public class DataSourceProperties {
/**
* 默认数据源
*/
private DataSourcePropertyDetail base;
/**
* 其他数据源
*/
private List<DataSourcePropertyDetail> list;
}
数据源配置
public class DynamicDataSource extends AbstractRoutingDataSource {
// 线程本地存储,线程私有区域,当前线程只能操作当前线程的局部变量
private static final ThreadLocal<String> contextHolder = new ThreadLocal<>();
// 存储数据源的集合
private Map<Object, Object> dynamicTargetDataSources = new HashMap<>();
@Override
protected Object determineCurrentLookupKey() {
if (StringUtils.isEmpty(getDataSource())) {
return "default";
}
return getDataSource();
}
// 设置默认数据源
@Override
public void setDefaultTargetDataSource(Object defaultTargetDataSource) {
super.setDefaultTargetDataSource(defaultTargetDataSource);
}
// 设置数据源
@Override
public void setTargetDataSources(Map<Object, Object> targetDataSources) {
super.setTargetDataSources(targetDataSources);
}
// 切换数据源,更改ThreadLocal中的局部变量
public static void switchDataSource(String dataSource) {
contextHolder.set(dataSource);
}
// 获取数据源
public static String getDataSource() {
return contextHolder.get();
}
// 删除数据源
public static void clearDataSource() {
contextHolder.remove();
}
// 创建数据源
public boolean createDataSource(List<DataSourcePropertyDetail> list) {
for (Iterator iterator = list.iterator(); iterator.hasNext();) {
DataSourcePropertyDetail db = (DataSourcePropertyDetail) iterator.next();
// 测试连接
testConnection(db.getDriverClassName(), db.getUrl(), db.getUsername(), db.getPassword());
// 连接数据库
DruidDataSource dataSource = new DruidDataSource();
dataSource.setName(db.getName());
dataSource.setUrl(db.getUrl());
dataSource.setDriverClassName(db.getDriverClassName());
dataSource.setUsername(db.getUsername());
dataSource.setPassword(db.getPassword());
// 设置最大连接等待时间
dataSource.setMaxWait(60000);
// 数据源初始化
try {
dataSource.init();
} catch (SQLException e) {
// 创建失败则抛出异常
throw new RuntimeException("データ ソースの作成に失敗しました");
}
this.dynamicTargetDataSources.put(db.getName(), dataSource);
// 设置数据源
this.setTargetDataSources(this.dynamicTargetDataSources);
// 解析数据源
super.afterPropertiesSet();
// 切换数据源
// setDataSource(dataSourceName);
}
return true;
}
// 测试连接
public void testConnection(String driveClass, String url, String username, String password) {
try {
Class.forName(driveClass);
DriverManager.getConnection(url, username, password);
} catch (Exception e) {
e.printStackTrace();
throw new RuntimeException("接続に失敗しました");
}
}
}
@Configuration
@EnableTransactionManagement
public class DataSourceConfig {
@Autowired
private DataSourceProperties dataSourceProperties;
@Bean(name = "dynamicDataSource")
public DynamicDataSource dataSource() {
// 设置默认数据源
DruidDataSource datasource = new DruidDataSource();
datasource.setUrl(dataSourceProperties.getBase().getUrl());
datasource.setUsername(dataSourceProperties.getBase().getUsername());
datasource.setPassword(dataSourceProperties.getBase().getPassword());
datasource.setDriverClassName(dataSourceProperties.getBase().getDriverClassName());
datasource.setName(dataSourceProperties.getBase().getName());
DynamicDataSource dynamicDataSource = new DynamicDataSource();
Map<Object, Object> targetDataSources = new HashMap<>();
targetDataSources.put(dataSourceProperties.getBase().getName(), datasource);
dynamicDataSource.setTargetDataSources(targetDataSources);
dynamicDataSource.setDefaultTargetDataSource(datasource);
//
// 设置其他数据源
dynamicDataSource.createDataSource(dataSourceProperties.getList());
return dynamicDataSource;
}
}
测试
mapper:
@Mapper
public interface DataSourceMapper {
public String test1();
public String test2();
}
xml:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.zx.SpringBootDemo.mapper.DataSourceMapper">
<select id="test1" resultType="string">
SELECT username from sys_user WHERE id='001'
</select>
<select id="test2" resultType="string">
SELECT username FROM user WHERE id = 1
</select>
</mapper>
test:
@SpringBootTest
class SpringBootDemoApplicationTests {
@Autowired
private DataSourceMapper dataSourceMapper;
@Test
void test() {
System.err.println(dataSourceMapper.test1());
// 切换数据源
DynamicDataSource.switchDataSource("b");
System.err.println(dataSourceMapper.test2());
DynamicDataSource.switchDataSource("default");
System.err.println(dataSourceMapper.test1());
}
}