SpringBoot多数据源基于mybatis插件(三)

SpringBoot多数据源基于mybatis插件(三)

1.主要思路

MyBatis的插件机制允许你在MyBatis的四大对象(Executor、StatementHandler、ParameterHandler和ResultSetHandler)的方法执行前后进行拦截,并可以在方法执行前后插入自定义逻辑。

这里其实就是利用Exector对象执行多数据操作,通过判断操作的类型来动态选择数据源。

在这里插入图片描述

2.具体实现

以下是一个Springboot整合mybatis的案例:

在这里插入图片描述yml文件配置:

spring:
  datasource:
    datasource1:
      driver-class-name: com.mysql.cj.jdbc.Driver
      jdbc-url: jdbc:mysql://localhost:3306/test_master
      username: root
      password: root
      druid:
         initial-size: 1
         min-idle: 1
         max-active: 20
         test-on-borrow: true

    datasource2:
      driver-class-name: com.mysql.cj.jdbc.Driver
      jdbc-url: jdbc:mysql://localhost:3306/test_slave
      username: root
      password: root
      druid:
        initial-size: 1
        min-idle: 1
        max-active: 20
        test-on-borrow: true


mybatis:
  type-aliases-package: com.rql.entity
  mapper-locations: classpath:mybatis/*.xml

DataSourceConfig.java
@Configuration
public class DataSourceConfig {

    @Bean
    @ConfigurationProperties(prefix = "spring.datasource.datasource1")
    public DataSource dataSource1(){
        return DataSourceBuilder.create().build();
    }

    @Bean
    @ConfigurationProperties(prefix = "spring.datasource.datasource2")
    public DataSource dataSource2(){
        return DataSourceBuilder.create().build();
    }

    @Bean
    public Interceptor DynamicDataSourcePlugin(){
        return new DynamicDataSourcePlugin();
    }
}

DynamicDataSourcePlugin.java
@Intercepts({@Signature(type = Executor.class,method = "update",args = {MappedStatement.class,Object.class}),
        @Signature(type = Executor.class,method = "query",args = {MappedStatement.class,Object.class, RowBounds.class,
                ResultHandler.class})})
public class DynamicDataSourcePlugin implements Interceptor {

    @Override
    public Object intercept(Invocation invocation) throws Throwable {
        //拿到当前方法【update、query】的所有参数
        Object[] objects = invocation.getArgs();
        //MappedStatement 封装sql
        MappedStatement ms = (MappedStatement) objects[0];
        //读方法
        if (ms.getSqlCommandType().equals(SqlCommandType.SELECT)) {

            DynamicDataSource.name.set("r");
        } else {//写方法
            DynamicDataSource.name.set("w");
        }
        return invocation.proceed();
    }

    @Override
    public Object plugin(Object target) {
        if (target instanceof Executor) {
            return Plugin.wrap(target, this);
        } else {
            return target;
        }
    }

    @Override
    public void setProperties(Properties properties) {

    }

}

  • @Intercepts注解:

@Intercepts :注解用于指定该插件要拦截的目标方法和参数。
@Signature :注解用于指定要拦截的接口、方法及其参数类型。在这个例子中,插件拦截了 Executor 接口的 updatequery 方法。

  • intercept方法:

这是插件的核心方法,当被拦截的方法被调用时,这个方法会被执行。
通过 Invocation 对象,可以获取到被拦截方法的参数,并可以执行被拦截的方法。
在这里,根据SQL的类型(读或写),使用 DynamicDataSource.name.set() 方法来设置不同的数据源(假设 DynamicDataSource 这里设置为 “r” 代表读数据源,“w” 代表写数据源)。

DynamicDataSource.java
@Component
@Primary
public class DynamicDataSource extends AbstractRoutingDataSource {

    public static ThreadLocal<String> name=new ThreadLocal<>();

    @Autowired
    DataSource dataSource1;

    @Autowired
    DataSource dataSource2;


    @Override
    protected Object determineCurrentLookupKey() {
        return name.get();
    }

    @Override
    public void afterPropertiesSet() {

        //targetDataSources初始化数据源
        HashMap<Object, Object> targetDataSources = new HashMap<>();
        targetDataSources.put("w", dataSource1);
        targetDataSources.put("r", dataSource2);
        super.setTargetDataSources(targetDataSources);

        //为defaultTargetDataSource设置默认数据源
        super.setDefaultTargetDataSource(dataSource1);

        super.afterPropertiesSet();
    }
}

同时,需要将DynamicDataSourcePlugin 的Bean注入到Spring容器中

    @Bean
    public Interceptor DynamicDataSourcePlugin(){
        return new DynamicDataSourcePlugin();
    }

  • 4
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值