Springboot 动态切换数据源

本文介绍了如何在Springboot应用中实现动态切换数据源,从添加依赖到配置数据源,再到实体类和数据源的具体配置,最后通过测试验证了数据源的切换功能。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

添加依赖

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());
		
	}

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值