使用sharding-jdbc解决SaaS系统动态数据源问题2——回答粉丝问题

在上篇文章:使用sharding-jdbc解决SaaS系统动态数据源问题 文章中有些细节没有罗列,给部分读者造成疑惑统一在这里解答:

1. 配置的动态数据源事务如何控制?

其实无论我们创建了多少个数据源,都是交到了shardingjdbc里面进行管理了,shardingjdbc内部管理一个dataSourceMap,然后shardingjdbc对其dataSourceMap进行封装出一个新的dataSourceNew,我们接下来只需要对新的dataSourceNew将其交给spring进行事务管理就可以了;
比如:

@Bean("shardingDataSource")
@Primary
public DataSource shardingDataSource(HikariDataSource hikariDataSource) throws SQLException {
    Map<String, DataSource> dataSourceMap = new HashMap<>(16);
    dataSourceMap.put(dataSourceName, hikariDataSource);
    ShardingRuleConfiguration shardingRuleConfig = new ShardingRuleConfiguration();
    HintShardingStrategyConfiguration hintShardingStrategyConfiguration
            = new HintShardingStrategyConfiguration(new DataSourceTypeHintShardingAlgorithm());
    shardingRuleConfig.setDefaultDatabaseShardingStrategyConfig(hintShardingStrategyConfiguration);
    shardingRuleConfig.setDefaultDataSourceName(dataSourceName);
    return ShardingDataSourceFactory.createDataSource(dataSourceMap, shardingRuleConfig, new Properties());
}

@Bean(name = "mysqlTransactionManager")
@Primary
public DataSourceTransactionManager mysqlTransactionManager(@Qualifier("shardingDataSource") DataSource dataSource) {
    return new DataSourceTransactionManager(dataSource);
}

如果你的使用场景和我不同,比如会牵扯到分布式事务的话,也可以集成seata,将事务控制交给seata实现;

2. shardingjdbc Hint分片策略只在当前线程有效

ShardingSphere使用ThreadLocal管理分片键值进行Hint强制路由。可以通过编程的方式向HintManager中添加分片值,该分片值仅在当前线程内生效。 Hint方式主要使用场景:
1.分片字段不存在SQL中、数据库表结构中,而存在于外部业务逻辑。
2.强制在主库进行某些数据操作。

而我们使用的正是shardingjdbc的Hint模式来解决动态创建数据源的,那岂不是这种方式不能对代码做异步?

@Override
@Transactional(rollbackFor = Exception.class)
public Response update() {
    try {
        String tenantName = "user1";
        HintManager.getInstance().setDatabaseShardingValue(tenantName);
        Student student = new Student();
        student.setId(2);
        student.setName("tom");
        int num = studentMapper.updateByPrimaryKey(student);
        // 异步
        new Thread(new BomRunnable(studentMapper)).start();

    } finally {
        HintManager.clear();
    }
    return ResponseBuilder.buildSuccess(num);
}

class BomRunnable implements Runnable{

    private StudentMapper studentMapper;

    public BomRunnable(StudentMapper studentMapper) {
        this.studentMapper = studentMapper;
    }

    @Override
    public void run() {
        Student student = new Student();
        student.setId(1);
        student.setName("jack");
        studentMapper.updateByPrimaryKey(student);
    }
}

这种情况,在异步处理的时候,其它已经找不到父线程所指定user1的数据源了,即会使用默认数据源,会造成权限越界,处理方式也很简单,如果异步方法里面能够获取到父线程的租户名称,是不是在子线程中再手动HintManager.getInstance().setDatabaseShardingValue(tenantName); 切换一下数据源就可以了;
至于父子线程如果传值问题,建议参考我的另一篇文章,ThreadLocal父子线程值传递问题 里面有详细的解法;

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值