Solon

solon.data.dynamicds

v2.7.3 native </> markdown
<dependency>
    <groupId>org.noear</groupId>
    <artifactId>solon.data.dynamicds</artifactId>
</dependency>

1、描述

数据扩展插件,为 Solon Data 提供了 动态数据源 的能力扩展。(v1.11.1 之后支持)

动态数据源,常见的合适场景:

  • 主从数据架构
  • 互备数据架构
  • 读写分离数据架构

提醒:

  • 动态数据源的内部切换是借用 ThreadLocal 实现
  • 多个动态数据源时,用的是同一个 ThreadLocal(多个时,要注意这个细节)
  • 一个服务内,最好只有一个动态源
  • 有更丰富的需求时,可基于 solon.data::AbstractRoutingDataSource 自己定制
  • 与事务注解一起使用时,会失效!!!

2、配置示例

# db_order 为固定数据源
test.db_order:
  schema: db_order
  jdbcUrl: jdbc:mysql://localhost:3306/db_order?useUnicode=true&characterEncoding=utf8&autoReconnect=true&rewriteBatchedStatements=true
  driverClassName: com.mysql.cj.jdbc.Driver
  username: root
  password: 123456

# db_user 为动态数据源(主菜是这里!!!)
test.db_user:
  type: "com.zaxxer.hikari.HikariDataSource"
  strict: true #严格模式(指定的源不存时:严格模式会抛异常;非严格模式用默认源)
  default: "db_user_1" #指定默认数据源
  db_user_1: 
    schema: db_user
    jdbcUrl: jdbc:mysql://localhost:3306/db_user?useUnicode=true&characterEncoding=utf8&autoReconnect=true&rewriteBatchedStatements=true
    driverClassName: com.mysql.cj.jdbc.Driver
    username: root
    password: 123456
  db_user_2:
    schema: db_user
    jdbcUrl: jdbc:mysql://localhost:3307/db_user?useUnicode=true&characterEncoding=utf8&autoReconnect=true&rewriteBatchedStatements=true
    driverClassName: com.mysql.cj.jdbc.Driver
    username: root
    password: 123456

2、应用示例

//配置数据源 bean
@Configuration
public class Config {
    //固定数据源
    @Bean("db_order")
    public DataSource dbOrder(@Inject("${test.db_order}") HikariDataSource dataSource) {
        return dataSource;
    }
    
    //动态数据源(直接注入)
    @Bean("db_user")
    public DataSource dbUser(@Inject("${test.db_user}") DynamicDataSource dataSource) {
        return dataSource;
    }
    
    //动态数据源(手动构建)//只是示例一下
    //@Bean("db_user")
    public DataSource dsUser2(@Inject("$demo.ds.db_user}") Properties props) {
        //手动构建,可以不用配置:type, strict
        Map<String, DataSource> dsMap = DsUtils.buildDsMap(props, HikariDataSource.class);
        DataSource dsDef = dsMap.get("default");
        
        DynamicDataSource tmp = new DynamicDataSource();
        tmp.setStrict(true);
        tmp.setTargetDataSources(dsMap);
        tmp.setDefaultTargetDataSource(dsDef);
        
        return tmp;
    }
}

@Component
public class UserService{
    @Db("db_order")
    OrderMapper orderMapper;
    
    @Db("db_user")
    UserMapper userMapper;
    
    @DynamicDs //使用 db_user 动态源内的 默认源
    public void addUser(){
        userMapper.inserUser();
    }
    
    //注解设置二级源
    @DynamicDs("db_user_1") //使用 db_user 动态源内的 db_user_1 源
    public void getUserList(){
        userMapper.selectUserList();
    }
    
    public void getUserList2(){
        //手动设置二级源
        DynamicDsKey.setCurrent("db_user_2"); //使用 db_user 动态源内的 db_user_2 源
        userMapper.selectUserList();
    }
}

3、通过纯代码创建和网络管理

@Configuration
public class DemoConfig {
    @Bean
    public DynamicDataSource dsInit(){
        DynamicDataSource ds = new DynamicDataSource();
        ds.setDefaultTargetDataSource(...); //设置默认的源 //也可能没有默认
        return ds;
    }
}

@Controller
public class DemoController{
    @Inject
    DynamicDataSource ds;
  
    //添加
    @Mapping("ds/add")
    public void dsAdd(String dsName, String dsProps){
        Props props = new Props();
        props.loadAdd(Utils.buildProperties(dsProps));
        DataSource ds = props.getBean(HikariDataSource.class);
        
        ds.addTargetDataSource(dsName, ds);
    }
    
    //注解设置二级源
    @DynamicDs("${dsName}") //注解设置当前取用哪源
    @Mapping("ds/use")
    public void dsUse(String dsName){
        ...
        
        //如果想直接拿到数据源对象:ds.getTargetDataSource(dsName);
        //除了注解设置二级源,还可以手动设置:DynamicDsKey.setCurrent(dsName); 
    }
}

具体参考

https://gitee.com/noear/solon-examples/tree/main/4.Solon-Data/demo4002-dynamicds