Spring动态数据源与运行时动态添加数据源

1、多数据源与动态数据源

当项目不只是要用到一个数据库的时候就需要使用到多个数据源了,这种场景很多,比如要查找的数据不在同一个数据库库中,或者是要做数据库读写分离。应对上面的问题主要有两种解决方法。

第一种:在Spring中注入多个DataSource,然后根据不同的DataSource生成不同的SqlSessionFactory,把要操作不同数据库的mapper接口放在不同的包下,并且使用MyBatis的@MapperScan注解,使用不同的SqlSessionFactory扫描不同包下的mapper接口。

例如:

第一步:向Spring中注入多个数据源
@Bean("db1-DataSource")
@Primary//注意这个@Primary注解是必须的,必须要有一个数据源加上这个注解,否则SpringBoot无法启动
@ConfigurationProperties(prefix = "datasource.db1")
fun db1DataSource(): DataSource {
    return DataSourceBuilder.create().build()
}

@Bean("db2-DataSource")
@ConfigurationProperties(prefix = "datasource.db2")
fun db2DataSource(): DataSource {
    return DataSourceBuilder.create().build()
}

第二步:生成多个SqlSessionFactory并注入Spring
@Bean("db1-SqlSessionFactory")
fun db1SqlSessionFactory(@Qualifier("db1-DataSource") ds: DataSource): SqlSessionFactory {
    val fb = SqlSessionFactoryBean()
    fb.setDataSource(ds)
    fb.setMapperLocations("你的mapper的xml文件位置")
    return fb.getObject()
}

@Bean("db2-SqlSessionFactory")
fun db2SqlSessionFactory(@Qualifier("db2-DataSource") ds: DataSource): SqlSessionFactory {
    val fb = SqlSessionFactoryBean()
    fb.setDataSource(ds)
    fb.setMapperLocations("你的mapper的xml文件位置")
    return fb.getObject()
}

第三步:@MapperScan使用不同的SqlSessionFactory扫描不同包下的mapper接口生成代理对象,假设要操作db1数据库的mapper接口放在app.mapper.db1包下,要操作db2数据库的mapper接口放在app.mapper.db2包下

@MapperScan(value = ["app.mapper.db1"], sqlSessionFactoryRef = "db1-SqlSessionFactory")

@MapperScan(value = ["app.mapper.db2"], sqlSessionFactoryRef = "db2-SqlSessionFactory")

这样不同包下的mapper接口就可以操作不同的数据库了。

接下来详细介绍第二种方法。

第二种:使用Spring提供的动态数据源AbstractRoutingDataSource

AbstractRoutingDataSource是一个抽象类,他实现了DataSource接口,内部可以存放多个DataSource,可以在需要的时候返回不同的DataSource。

接下来解析AbstractRoutingDataSource的部分源码:

//AbstractRoutingDataSource的内部使用了一个map存放多个数据源,key是数据源的唯一名字(可以任意命名,但是要保证唯一),value是对应的DataSource

private Map<Object, Object> targetDataSources;
//提供一个默认使用的数据源
private Object defaultTargetDataSource;
//这个是我们要实现的一个抽象方法,返回值是DataSource的唯一名字,表示使用该名字对应的DataSource
protected abstract Object determineCurrentLookupKey();
//这个是决定使用哪个数据源的方法,根据determineCurrentLookupKey的返回值来决定
protected DataSource determineTargetDataSource() {
    Object lookupKey = determineCurrentLookupKey();
	DataSource dataSource = this.resolvedDataSources.get(lookupKey);
	if (dataSource == null && (this.lenientFallback || lookupKey == null)) {
		dataSource = this.resolvedDefaultDataSource;
	}

	if (dataSource == null) {
		
评论 9
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值