基于AbstractRoutingDataSource的动态切换数据库

当项目发展到一定阶段,就需要对数据库进行一定的优化。一般会对数据库进行横向和纵向切库分表,但是这样的问题就来了,在我们操作数据库时,需要根据切分规则提前获得我们需要的数据库的连接,这明显会加重程序员的负担。
比如我们将“用户信息数据库”按照用户注册的年月来分库,在用户注册的时候,为用户分配一个以yyyyMM开头的唯一标示,以方便我们能快速定位到切分后的子数据库。那么问题来了,我们在项目中,如何动态且方便的获得我们需要的数据源呢?Spring提供了一个解决方案,那就是基于AbstractRoutingDataSource的动态数据源切换。
AbstractRoutingDataSource的类结构:
这里写图片描述

想要使用,只需要重写determineCurrentLookupKey方法,在说明他的作用之前,先看下调用他的位置:

private Map<Object, DataSource> resolvedDataSources;

	protected DataSource determineTargetDataSource() {
		Assert.notNull(this.resolvedDataSources, "DataSource router not initialized");
		Object lookupKey = determineCurrentLookupKey();
		DataSource dataSource = this.resolvedDataSources.get(lookupKey);
		if (dataSource == null && (this.lenientFallback || lookupKey == null)) {
			dataSource = this.resolvedDefaultDataSource;
		}
		if (dataSource == null) {
			throw new IllegalStateException("Cannot determine target DataSource for lookup key [" + lookupKey + "]");
		}
		return dataSource;
	}

可以看到,determineCurrentLookupKey的返回值会作为Map的key来查找数据库连接。而determineTargetDataSource方法通常是用来返回给调用端DataSource,因此我们可以通过重写这两个方法,来实现动态切换数据库。

首先定义一个Bean来保存数据库信息,也将它作为Map的key,数据库连接作为Value。

public class DatabaseDefineBean {
	private String userName;
	private String passWord;
	private String url;

	...getter/setter
}

编写我们自己的数据源

public class MyDataSource extends AbstractRoutingDataSource {
	private String driverClassName;
	static ThreadLocal<DatabaseDefineBean> defineBeans = new ThreadLocal<DatabaseDefineBean>();
	
	@Override
	protected Object determineCurrentLookupKey() {
		return defineBeans.get();
	}

	@Override
	protected DataSource determineTargetDataSource() {
		DriverManagerDataSource dataSource = getDataSource((DatabaseDefineBean) determineCurrentLookupKey());
		return dataSource;
	}

	private DriverManagerDataSource getDataSource(DatabaseDefineBean databse) {
		DriverManagerDataSource dataSource = new DriverManagerDataSource(databse.getUrl(), databse.getUserName(),
				databse.getPassWord());

		return dataSource;
	}
}

这里使用Spring+Mybatis测试(源码及数据库文件下载):

	String userName = "writeuser";
	String passWord = "writeuser";
	String url = "jdbc:mysql://192.168.1.61:3306/DataBaseRoute";
	
	@Test
	public void test() {
		ApplicationContext context = new ClassPathXmlApplicationContext(new String[]{"/com/smart/config/spring-jdbc.xml"});
		MyDataSource.setDefineBeans(new DatabaseDefineBean(userName, passWord, url));
		DataSource dataSource = context.getBean(DataSource.class);
		
		System.out.println(dataSource);
		
		SqlSessionTemplate sessionTemplate =  context.getBean(SqlSessionTemplate.class);		
	
		DatabaseInfoMapper mapper = sessionTemplate.getSqlSessionFactory().openSession().getMapper(DatabaseInfoMapper.class);
		List<?> list = mapper.selectAll();
		System.out.println(list);
	}

那么如何动态切换呢?这里使用到了ThreadLocal,用于为每个线程保存一个副本,我们只需在操作数据库之前设置一下Database的基本信息就可以轻松获得想要的数据源了。

MyDataSource.setDefineBeans(new DatabaseDefineBean(userName, passWord, url));

在这里插入图片描述

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
在Spring Boot中,可以通过使用AbstractRoutingDataSource类来实现JDBC动态切换数据库。 具体实现步骤如下: 1. 创建一个继承自AbstractRoutingDataSource的类,例如DynamicDataSource。 2. 重写determineCurrentLookupKey()方法,该方法根据特定的规则动态返回当前需要使用的数据源的key。例如,可以从ThreadLocal中获取当前请求的数据源key。 3. 在application.yml或application.properties文件中配置多个数据源的属性,例如: ``` spring.datasource.datasource1.url=jdbc:mysql://localhost:3306/db1 spring.datasource.datasource1.username=root spring.datasource.datasource1.password=123456 spring.datasource.datasource2.url=jdbc:mysql://localhost:3306/db2 spring.datasource.datasource2.username=root spring.datasource.datasource2.password=123456 ``` 4. 在Spring Boot的配置类中使用DynamicDataSource作为数据源,并将多个数据源的属性配置注入到DynamicDataSource中,例如: ``` @Configuration public class DataSourceConfig { @Bean @ConfigurationProperties(prefix = "spring.datasource.datasource1") public DataSource dataSource1() { return DataSourceBuilder.create().build(); } @Bean @ConfigurationProperties(prefix = "spring.datasource.datasource2") public DataSource dataSource2() { return DataSourceBuilder.create().build(); } @Bean public DynamicDataSource dynamicDataSource() { DynamicDataSource dynamicDataSource = new DynamicDataSource(); Map<Object, Object> dataSourceMap = new HashMap<>(); dataSourceMap.put("datasource1", dataSource1()); dataSourceMap.put("datasource2", dataSource2()); dynamicDataSource.setTargetDataSources(dataSourceMap); dynamicDataSource.setDefaultTargetDataSource(dataSource1()); return dynamicDataSource; } } ``` 5. 在需要使用数据源的地方,使用@Qualifier注解指定要使用的数据源的key,例如: ``` @Autowired @Qualifier("datasource1") private DataSource dataSource; ``` 这样,在运行时,根据特定的规则动态切换数据源,就可以实现JDBC动态切换数据库了。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值