创建多个数据源
1.先配置说有数据库
2.并将数据库添加DynamicRoutingDataSource这个动态数据库中
3.并设置了目标数据源和配置的数据源
4.配置的数据源以map形式存放,
5.然后将DynamicRoutingDataSource数据源传递给了mybatis,
mybatis操作数据库就是通过他来操作
@Configuration
@MapperScan("com.dw.seata.multiple.mapper")
public class DataSourceProxyConfig {
?
? ?@Bean("originOrder")
? ?@ConfigurationProperties(prefix = "spring.datasource.order")
? ?public DataSource dataSourceMaster() {
? ? ? ?return new DruidDataSource();
? }
?
? ?@Bean("originStorage")
? ?@ConfigurationProperties(prefix = "spring.datasource.storage")
? ?public DataSource dataSourceStorage() {
? ? ? ?return new DruidDataSource();
? }
?
? ?@Bean("originAccount")
? ?@ConfigurationProperties(prefix = "spring.datasource.account")
? ?public DataSource dataSourceAccount() {
? ? ? ?return new DruidDataSource();
? }
?
?
? ?@Bean("dynamicDataSource")
? ?public DataSource dynamicDataSource(@Qualifier("originOrder") DataSource dataSourceOrder,
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?@Qualifier("originStorage") DataSource dataSourceStorage,
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?@Qualifier("originAccount") DataSource dataSourceAccount) {
?
? ? ? ?DynamicRoutingDataSource dynamicRoutingDataSource = new DynamicRoutingDataSource();
?
? ? ? ?// 数据源的集合
? ? ? ?Map<Object, Object> dataSourceMap = new HashMap<>(3);
? ? ? ?dataSourceMap.put(DataSourceKey.ORDER.name(), dataSourceOrder);
? ? ? ?dataSourceMap.put(DataSourceKey.STORAGE.name(), dataSourceStorage);
? ? ? ?dataSourceMap.put(DataSourceKey.ACCOUNT.name(), dataSourceAccount);
?
? ? ? ?// 设置默认的数据源
? ? ? ?dynamicRoutingDataSource.setDefaultTargetDataSource(dataSourceOrder);
? ? ? ?// 设置目标数据源
? ? ? ?dynamicRoutingDataSource.setTargetDataSources(dataSourceMap);
?
? ? ? ?DynamicDataSourceContextHolder.getDataSourceKeys().addAll(dataSourceMap.keySet());
?
? ? ? ?return dynamicRoutingDataSource;
? }
?
? ?@Bean
? ?@ConfigurationProperties(prefix = "mybatis")
? ?public SqlSessionFactoryBean sqlSessionFactoryBean(@Qualifier("dynamicDataSource") DataSource dataSource) {
? ? ? ?SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();
? ? ? ?sqlSessionFactoryBean.setDataSource(dataSource);
?
? ? ? ?org.apache.ibatis.session.Configuration configuration=new org.apache.ibatis.session.Configuration();
? ? ? ?//使用jdbc的getGeneratedKeys获取数据库自增主键值
? ? ? ?configuration.setUseGeneratedKeys(true);
? ? ? ?//使用列别名替换列名
? ? ? ?configuration.setUseColumnLabel(true);
? ? ? ?//自动使用驼峰命名属性映射字段,如userId ---> user_id
? ? ? ?configuration.setMapUnderscoreToCamelCase(true);
? ? ? ?sqlSessionFactoryBean.setConfiguration(configuration);
?
? ? ? ?return sqlSessionFactoryBean;
? }
?
}
2 创建DynamicRoutingDataSource
DynamicRoutingDataSource继承了AbstractRoutingDataSource,并且重写了determineCurrentLookupKey方法,
这个方法,是在getConnection时候我们会调用这个方法活去对应的key,然后再对应我们的map数据库集合中获取对应的数据源。后面我们在源码讲解
@Slf4j
public class DynamicRoutingDataSource extends AbstractRoutingDataSource {
/**
* 该方法的返回值就是项目中所要用的DataSource的key值,
* 拿到该key后就可以在resolvedDataSource中取出对应的DataSource,
* 如果key找不到对应的DataSource就使用默认的数据源。
* @return
*/
@Override
protected Object determineCurrentLookupKey() {
log.info("当前数据源 [{}]", DynamicDataSourceContextHolder.getDataSourceKey());
return DynamicDataSourceContextHolder.getDataSourceKey();
}
public static void main(String[] args) {
System.out.println(DynamicDataSourceContextHolder.getDataSourceKey());
}
}
3 创建切面
我们对应的service 上都是有@Datasource注解,这个注解DynamicDataSourceAspect会在方法调用的时候进行拦截,在方法之间会解析@Datasource中的值,会将其设置到ThreadLocal里面,这里面DynamicDataSourceContextHolder,然后调用mybatis时候获取链接的时候时候会带调用上面的类determineCurrentLookupKey获取对应的key,我们通过这个key可以获取对应的数据源
@Aspect
@Component
public class DynamicDataSourceAspect {
private static final Logger logger = LoggerFactory.getLogger(DynamicDataSourceAspect.class);
@Before("@annotation(ds)")
public void changeDataSource(JoinPoint point, DataSource ds) throws Throwable {
DataSourceKey dsId = ds.value();
if (DynamicDataSourceContextHolder.isContainsDataSource(dsId.name())) {
DynamicDataSourceContextHolder.setDataSourceKey(dsId);
logger.debug("Use DataSource :{} >", dsId, point.getSignature());
} else {
logger.error("数据源[{}]不存在,使用默认数据源 >{}", dsId, point.getSignature());
}
}
@After("@annotation(ds)")
public void restoreDataSource(JoinPoint point, DataSource ds) {
logger.debug("Revert DataSource : " + ds.value() + " > " + point.getSignature());
DynamicDataSourceContextHolder.clearDataSourceKey();
}
}
首先我们给DynamicRoutingDataSource设置数据源setTargetDataSources 是一个map数据源,设置完后afterPropertiesSet方法里面会将我们设置的map设置到我们的resovledDataSources中
当我调用getConnnection时候会调用DetermineTargetDataSources方法,这个方法会调用我们重写的determineCourrentLookupKey,从而获取数据源对应的ekey
最后 通过key从resolveDataSources中获取了对应的数据源。