为什么数据库需要配置读写分离f
实现的原理
实现的原理主要分为两种:
1.静态的选择Master/Slave数据库(通过单独配置读写库,在方法中已经写死使用读库或者写库)
2.数据库选择是动态切换(这里写的是这种方式实现读写分离)
动态获取连接的流程:
ps:我们的ReadWriteDataSourceConfig需要继承于AbstractRoutingDataSource
1.AbstractRoutingDataSource初始化会依赖注入配置文件中你所配置的DataSource, 并保存于Map中(结构为key-DataSource,其中key为配置文件中设置的,key是为了标识对应的数据库,后续动态获取时会从ThreadLocal中获取key)
2.通过aop拦截注解DBReadOnly(自定义),readDataSource的key保存于ThreadLocal中。
3.获取数据库链接时,AbstractRoutingDataSource会调用覆写的getConnetion,其中getConnetion方法会调用determineTargetDataSource方法,它会调用抽象方法determineCurrentLookupKey(目的就是为了获取对应保存数据库的Map的key),我们的ReadWriteDataSourceConfig需要覆写determineCurrentLookupKey方法,返回ThreadLocal中的key(如果Key不存在,会使用默认库,下面会详细介绍),从而AbstractRoutingDataSource会去获取对应的数据库连接,实现动态获取数据库连接。
实现的原理:
/**
* <p>Attempts to establish a connection with the data source that
* this {@code DataSource} object represents.
*
* @return a connection to the data source
* @exception SQLException if a database access error occurs
* @throws java.sql.SQLTimeoutException when the driver has determined that the
* timeout value specified by the {@code setLoginTimeout} method
* has been exceeded and has at least tried to cancel the
* current database connection attempt
*/
Connection getConnection()
throws
SQLException;
|
public
abstract
class
AbstractRoutingDataSource
extends
AbstractDataSource
implements
InitializingBean{
private
Map<Object, Object> targetDataSources;
//保存对应key的DataSource
private
Object defaultTargetDataSource;
//默认的使用的DataSource的Bean
private
boolean
lenientFallback =
true
;
private
DataSourceLookup dataSourceLookup =
new
JndiDataSourceLookup();
private
Map<Object, DataSource> resolvedDataSources;
//所有DateSource保存于这个Map中
private
DataSource resolvedDefaultDataSource;
//默认使用的DataSource,下面会详谈
@Override
public
void
afterPropertiesSet() {
if
(
this
.targetDataSources ==
null
) {
throw
new
IllegalArgumentException(
"Property 'targetDataSources' is required"
);
}
this
.resolvedDataSources =
new
HashMap<Object, DataSource>(
this
.targetDataSources.size());
for
(Map.Entry<Object, Object> entry :
this
.targetDataSources.entrySet()) {
//这是
Object lookupKey = resolveSpecifiedLookupKey(entry.getKey());
DataSource dataSource = resolveSpecifiedDataSource(entry.getValue());
this
.resolvedDataSources.put(lookupKey, dataSource);
}
if
(
this
.defaultTargetDataSource !=
null
) {
this
.resolvedDefaultDataSource = resolveSpecifiedDataSource(
this
.defaultTargetDataSource);
}
}
}
|
1.AbstractRoutingDataSource中的成员变量,和初始化所做的事情(转换并保存Map<key, DataSource>,可设置key不存在时候的默认DataSourcere)
AbstractRoutingDataSource中有targetDataSources,AbstractRoutingDataSource初始化会依赖注入配置文件中你所配置的DataSource, 并保存于Map中(结构为key-DataSource,其中key为配置文件中设置的,key是为了标识对应的数据库,后续动态获取时会从ThreadLocal中获取key),最终你所需要的数据库连接是通过你给于的key去获取,覆写determineCurrentLookupK