springboot 整合mybatis-plus+dynamic-datasource实现读写分离

第一步、导包

  数据源使用druid,这里druid和mybatis-plus版本不是最新,可自行选择。

	<dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid-spring-boot-starter</artifactId>
            <version>1.1.10</version>
        </dependency>
	<dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>dynamic-datasource-spring-boot-starter</artifactId>
            <version>3.1.0</version>
        </dependency>
	<dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
            <version>2.1.9</version>
        </dependency>			

第二步、写配置

  这里数据库使用的SqlServer,自行修改,oracle或mysql见jdbc快速入坑(一)

  • application.yml配置如下:
# Tomcat
server:
    tomcat:
        uri-encoding: UTF-8
        max-threads: 1000
        min-spare-threads: 30
    port: 8088
spring:
    datasource:
        type: com.alibaba.druid.pool.DruidDataSource
        driverClassName: com.microsoft.sqlserver.jdbc.SQLServerDriver
        druid:
            stat-view-servlet:
                enabled: true
                url-pattern: /druid/*
                loginUsername: admin
                loginPassword: 123456
        dynamic:
            primary: master
            health: true
            druid:
                initial-size: 10
                max-active: 100
                min-idle: 10
                max-wait: 60000
                pool-prepared-statements: true
                max-pool-prepared-statement-per-connection-size: 20
                time-between-eviction-runs-millis: 60000
                min-evictable-idle-time-millis: 300000
                test-while-idle: true
                test-on-borrow: false
                test-on-return: false
                validationQuery: "select 1"
                filters: stat,wall
                stat:
                    log-slow-sql: true
                    slow-sql-millis: 1000
                    merge-sql: false
                wall:
                    multi-statement-allow: true
            datasource:
                master:  #数据源1
                    url: jdbc:sqlserver://127.0.0.1:1051;databaseName=test
                    username: ENC(L36gh72XwqNKz00VQnxz9XhApDcpf5Q4oaW5nwbpE4e1TBGL81HxQcfI64eBXMiSTwI8+f70hW50aX2iZdFyBw==)
                    password: ENC(f4j9JTNqd7XkuSlDLM1od6AByM8zw/crcd4lo47l97JIWD62VvBXJK5EFBWV67We4wThc9r0oIc8tKdfsZbO5g==)
                slave:
                    url: jdbc:sqlserver://121.196.190.248:1050;databaseName=test
                    username: ENC(L36gh72XwqNKz00VQnxz9XhApDcpf5Q4oaW5nwbpE4e1TBGL81HxQcfI64eBXMiSTwI8+f70hW50aX2iZdFyBw==)
                    password: ENC(f4j9JTNqd7XkuSlDLM1od6AByM8zw/crcd4lo4Ml97JIWD62VvBXJK5EFBWV67We4wThc9r0oIc8tKdfsZbO5g==)
mybatis-plus:
    mapper-locations: classpath*:mapper/**/*.xml
    #实体扫描,多个package用逗号或者分号分隔
    typeAliasesPackage: com.test.*.entity
    global-config:
        #主键类型  0:"数据库ID自增", 1:"用户输入ID",2:"全局唯一ID (数字类型唯一ID)", 3:"全局唯一ID UUID";
        id-type: 0
        #字段策略 0:"忽略判断",1:"非 NULL 判断"),2:"非空判断"
        field-strategy: 1
        #驼峰下划线转换
        db-column-underline: true
        #刷新mapper 调试神器
        refresh-mapper: true
        #数据库大写下划线转换
        #capital-mode: true
        # Sequence序列接口实现类配置
        #key-generator: com.baomidou.mybatisplus.incrementer.OracleKeyGenerator
        #逻辑删除配置
        logic-delete-value: -1
        logic-not-delete-value: 0
        #自定义填充策略接口实现
        #meta-object-handler: com.baomidou.springboot.xxx
        #自定义SQL注入器
        sql-injector: com.baomidou.mybatisplus.mapper.LogicSqlInjector
    configuration:
        map-underscore-to-camel-case: true
        cache-enabled: false
        call-setters-on-nulls: true
        #打印mybatis的执行sql
        log-impl: org.apache.ibatis.logging.stdout.StdOutImpl

  • 重写读写分离插件配置

import com.baomidou.dynamic.datasource.spring.boot.autoconfigure.DynamicDataSourceProperties;
import com.baomidou.dynamic.datasource.support.DbHealthIndicator;
import com.baomidou.dynamic.datasource.support.DdConstants;
import com.baomidou.dynamic.datasource.toolkit.DynamicDataSourceContextHolder;
import java.util.Properties;
import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.executor.Executor;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.mapping.SqlCommandType;
import org.apache.ibatis.plugin.Interceptor;
import org.apache.ibatis.plugin.Intercepts;
import org.apache.ibatis.plugin.Invocation;
import org.apache.ibatis.plugin.Plugin;
import org.apache.ibatis.plugin.Signature;
import org.apache.ibatis.session.ResultHandler;
import org.apache.ibatis.session.RowBounds;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.StringUtils;


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

    @Autowired
    private DynamicDataSourceProperties properties;

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

    /**
     * 获取动态数据源名称,重写注入 DbHealthIndicator 支持数据源健康状况判断选择
     *
     * @param mappedStatement mybatis MappedStatement
     * @return 获取真实的数据源名称
     */
    public String getDataSource(MappedStatement mappedStatement) {
        String slave = DdConstants.SLAVE;
        if (properties.isHealth()) {
            /*
             * 根据从库健康状况,判断是否切到主库
             */
            boolean health = DbHealthIndicator.getDbHealth(DdConstants.SLAVE);
            if (!health) {
                health = DbHealthIndicator.getDbHealth(DdConstants.MASTER);
                if (health) {
                    slave = DdConstants.MASTER;
                }
            }
        }
        return SqlCommandType.SELECT == mappedStatement.getSqlCommandType() ? slave : DdConstants.MASTER;
    }

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

    @Override
    public void setProperties(Properties properties) {
    }
}
  • 新建MybaitsPlus配置类MybatisPlusConfig
import com.baomidou.mybatisplus.plugins.PaginationInterceptor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class MybatisPlusConfig {
    /**
     * 分页插件
     */
    @Bean
    public PaginationInterceptor paginationInterceptor() {
        return new PaginationInterceptor();
    }

    /**
     * 读写分离插件
     */
    @Bean
    public MasterSlaveAutoRoutingPlugin masterSlaveAutoRoutingPlugin(){
        return new MasterSlaveAutoRoutingPlugin();
    }

}

  • 定义数据源常量
public interface DBConstants {
   String MASTER = "master";
   String SLAVE_GROUP = "slave";
   String SLAVE1 = "slave_1";
}

第三步、测试

  • 测试代码

@RequestMapping("/test")
@RestController
public class TestController {

    @Autowired
    private AreaService areaService;

    /**
     * 使用主库查询
     */
    @GetMapping
    @DS(DBConstants.MASTER)
    public Object test(){
        Wrapper<AreaEntity> wrapper = new EntityWrapper<>();
        return areaService.selectList(wrapper);
    }

    /**
     * 未加@DS注解,查询操作默认使用slave从库,插入操作默认使用master主库 
     */
    @GetMapping("/11")
    public Object test11(){
        Wrapper<AreaEntity> wrapper = new EntityWrapper<>();
        return areaService.selectList(wrapper);
    }

    /**
     *使用从库查询 
     */
    @GetMapping("/22")
    @DS(DBConstants.SLAVE_GROUP)
    public Object test22(){
        Wrapper<AreaEntity> wrapper = new EntityWrapper<>();
        return areaService.selectList(wrapper);
    }
}

  当未加@DS注解时,查询操作默认使用从库,修改删除和添加操作默认使用主库,如果添加@DS注解,则以注解为准。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值