基于mybatis-plus实现读写分离,无需使用@DS注解

想必大家在论坛上已经看过很多使用苞米豆的dynamic做读写分离的方法,依赖如下:

        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>dynamic-datasource-spring-boot-starter</artifactId>
            <version>${dynamic-ds.version}</version>
        </dependency>

版本3.5.2

内置的DS注解在注解上添加@DS("datasourceName")做读写分离,如果在项目早期,添加这个注解确实也是挺方便的,但是当项目快要完工了 代码量很多,一个个加上@DS注解会累死人的,所以我们可以在项目中创建一个类也可以不用,其主要原理是mybatis-plus框架的com.baomidou.dynamic.datasource.plugin包里的MasterSlaveAutoRoutingPlugin

@Configuration
public class MybatisPlusConfig {


    //mybatis-plus分页插件
    @Bean
    public PaginationInnerInterceptor paginationInnerInterceptor(){
        return new PaginationInnerInterceptor(DbType.MYSQL);
    }

    
    //mybatis-plus读写分离插件
    @Bean
    public MasterSlaveAutoRoutingPlugin masterSlaveAutoRoutingPlugin(){
        return new MyMasterSlaveAutoRoutingPlugin();
    }

    @Bean
    public MybatisPlusInterceptor mybatisPlusInterceptor() {
        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
        interceptor.addInnerInterceptor(paginationInnerInterceptor()); //注意使用哪种数据库
        return interceptor;
    }

}

这里的MasterSlaveAutoRoutingPlugin就是实现读写分离的插件,这里我继承了MasterSlaveAutoRoutingPlugin写了一个MyMasterSlaveAutoRoutingPlugin 其实没有改什么东西,只是加了一个lambok的log输出,MyMasterSlaveAutoRoutingPlugin代码如下:

@Slf4j
@Intercepts({@Signature(
        type = Executor.class,
        method = "query",
        args = {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class}
), @Signature(
        type = Executor.class,
        method = "query",
        args = {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class, CacheKey.class, BoundSql.class}
), @Signature(
        type = Executor.class,
        method = "update",
        args = {MappedStatement.class, Object.class}
)})
public class MyMasterSlaveAutoRoutingPlugin extends MasterSlaveAutoRoutingPlugin {

    @Override
    public Object intercept(Invocation invocation) throws Throwable {
        Object[] args = invocation.getArgs();
        MappedStatement ms = (MappedStatement)args[0];
        String pushedDataSource = null;

        Object var6;
        try {
            String dataSource = SqlCommandType.SELECT == ms.getSqlCommandType() ? "slave" : "master";
            log.info("===========================正在查询[{}]数据库,{}语句========================",dataSource,ms.getSqlCommandType());
            pushedDataSource = DynamicDataSourceContextHolder.push(dataSource);
            var6 = invocation.proceed();
        } finally {
            if (pushedDataSource != null) {
                DynamicDataSourceContextHolder.poll();
            }

        }

        return var6;
    }

}

MasterSlaveAutoRoutingPlugin代码:

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

    @Autowired
    protected DataSource dynamicDataSource;

    @Override
    public Object intercept(Invocation invocation) throws Throwable {
        Object[] args = invocation.getArgs();
        MappedStatement ms = (MappedStatement) args[0];
        String pushedDataSource = null;
        try {
            String dataSource = SqlCommandType.SELECT == ms.getSqlCommandType() ? DdConstants.SLAVE : DdConstants.MASTER;
            pushedDataSource = DynamicDataSourceContextHolder.push(dataSource);
            return invocation.proceed();
        } finally {
            if (pushedDataSource != null) {
                DynamicDataSourceContextHolder.poll();
            }
        }
    }

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

    @Override
    public void setProperties(Properties properties) {
    }

其中跟读写分离最重要的就是intercept方法,其原理就是判断mybaits-plus所执行的SQL语句是否是SELECT语句 如果是SELECT语句 则走从库,如果是其它语句 则走主库,从而实现读写分离,无需使用@DS注解,方便许多

让我们来看看最终的效果:

读从库:

写主库:

 

 

 

 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
MyBatis-Plus 是一个在 MyBatis 基础上进行增强的持久层框架,提供了很多方便开发的功能和工具。关于 MyBatis-Plus读写分离,可以通过配置动态数据源和使用 MyBatis-Plus 提供的注解实现读写分离是指将数据库的读操作和写操作分别在不同的数据库实例上进行,以提高系统的并发能力和性能。在 MyBatis-Plus 中,可以通过使用多个数据源来实现读写分离。 首先,需要配置多个数据源,一个用于读操作,一个用于写操作。可以使用 Spring Boot 提供的配置方式,或者使用 MyBatis-Plus 提供的 DynamicDataSource 动态数据源。 然后,在需要进行读操作的方法上,可以使用 MyBatis-Plus 提供的 @Slave 注解,指定使用读数据源。例如: ```java @Slave public List<User> getUserList() { // ... } ``` 在需要进行写操作的方法上,则不需要特别指定数据源,默认会使用主数据源。 最后,在 MyBatis-Plus 的配置文件中,需要配置动态数据源的切换策略。可以通过使用 AbstractRoutingDataSource 类来实现切换策略,根据方法上的注解来决定使用哪个数据源。 这样配置之后,当调用带有 @Slave 注解的方法时,MyBatis-Plus 会自动切换到读数据源;调用其他方法时,会使用写数据源。从而实现读写分离的功能。 需要注意的是,读写分离的配置还涉及到数据库的主从同步和数据一致性等问题,在配置过程中需要综合考虑这些因素。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值