多数据源分布式事务

1 操作多数据源

创建多个数据源

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中获取了对应的数据源。

80d97f8e9b44430a85802d9bdcf923a6.png

  • 7
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值