文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

mybatis中怎么实现读写分离

2023-06-20 19:29

关注

本篇文章为大家展示了mybatis中怎么实现读写分离,内容简明扼要并且容易理解,绝对能使你眼前一亮,通过这篇文章的详细介绍希望你能有所收获。

1、spring aop实现

首先application-test.yml增加如下数据源的配置

spring:  datasource:    master:      jdbc-url: jdbc:mysql://master域名:3306/test      username: root      password: 123456      driver-class-name: com.mysql.jdbc.Driver    slave1:      jdbc-url: jdbc:mysql://slave域名:3306/test      username: root   # 只读账户      password: 123456      driver-class-name: com.mysql.jdbc.Driver    slave2:      jdbc-url: jdbc:mysql://slave域名:3306/test      username: root   # 只读账户      password: 123456      driver-class-name: com.mysql.jdbc.Driver
package com.cjs.example.enums;public enum DBTypeEnum {    MASTER, SLAVE1, SLAVE2;}

定义ThreadLocal上下文,将当前线程的数据源进行动态修改

public class DBContextHolder {    private static  volatile ThreadLocal<DBTypeEnum> contextHolder = new ThreadLocal<>();    public static synchronized void set(DBTypeEnum dbType) {        contextHolder.set(dbType);    }    public static synchronized DBTypeEnum get() {        return contextHolder.get();    }    public static void master() {        set(DBTypeEnum.MASTER);    }    public static void slave() {        set(DBTypeEnum.SLAVE1);    }    public static void slave2(){ set(DBTypeEnum.SLAVE2); }    // 清除数据源名    public static void clearDB() {        contextHolder.remove();    }}

重写mybatis数据源路由接口,在此修改数据源为我们上一块代码设置的上下文的数据源

public class MyRoutingDataSource extends AbstractRoutingDataSource {    @Nullable    @Override    protected Object determineCurrentLookupKey() {        DBTypeEnum dbTypeEnum=DBContextHolder.get();        return dbTypeEnum;    }}

将yml配置的多数据源手动指定注入

@Configurationpublic class DataSourceConfig {    @Bean    @ConfigurationProperties("spring.datasource.master")    public DataSource masterDataSource() {        return DataSourceBuilder.create().build();    }    @Bean    @ConfigurationProperties("spring.datasource.slave1")    public DataSource slave1DataSource() {        return DataSourceBuilder.create().build();    }    @Bean    public DataSource myRoutingDataSource(@Qualifier("masterDataSource") DataSource masterDataSource,                                          @Qualifier("slave1DataSource") DataSource slave1DataSource) {        Map<Object, Object> targetDataSources = new HashMap<>();        targetDataSources.put(DBTypeEnum.MASTER, masterDataSource);        targetDataSources.put(DBTypeEnum.SLAVE1, slave1DataSource);        MyRoutingDataSource myRoutingDataSource = new MyRoutingDataSource();        myRoutingDataSource.setDefaultTargetDataSource(masterDataSource);        myRoutingDataSource.setTargetDataSources(targetDataSources);        return myRoutingDataSource;    }}

sqlsession注入以上我们配置的datasource路由

@EnableTransactionManagement@Configuration@Import({TableSegInterceptor.class})public class MyBatisConfig {    @Resource(name = "myRoutingDataSource")    private DataSource myRoutingDataSource;    @Autowired    private MybatisConfigProperty mybatisConfigProperty;    @Autowired    private TableSegInterceptor tableSegInterceptor;    @Bean    public SqlSessionFactory sqlSessionFactory() throws Exception {        SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();        sqlSessionFactoryBean.setDataSource(myRoutingDataSource);        // SpringBoot项目集成mybatis打包为jar运行时setTypeAliasesPackage无效解决        VFS.addImplClass(SpringBootVFS.class);        sqlSessionFactoryBean.setMapperLocations(                new PathMatchingResourcePatternResolver().getResources(mybatisConfigProperty.getMapperLocations()));        sqlSessionFactoryBean.setTypeAliasesPackage(mybatisConfigProperty.getTypeAliasesPackage());        sqlSessionFactoryBean.setConfigLocation(                new PathMatchingResourcePatternResolver().getResource(mybatisConfigProperty.getConfigLocation()));        sqlSessionFactoryBean.setPlugins(new Interceptor[]{tableSegInterceptor});        return sqlSessionFactoryBean.getObject();    }    @Bean    public PlatformTransactionManager platformTransactionManager() {        return new DataSourceTransactionManager(myRoutingDataSource);    }}

spring aop拦截指定前缀的service方法,并设置对应所属的上下文

@Aspect@Componentpublic class DataSourceAop {    @Pointcut("!@annotation(com.ask.student.interceptor.annotation.Master) " +            "&& (execution(* com.ask.student.service..*.select*(..)) " +            "|| execution(* com.ask.student.service..*.get*(..))" +            "|| execution(* com.ask.student.service..*.find*(..))" +            ")")    public void readPointcut() {    }    @Pointcut("@annotation(com.ask.student.interceptor.annotation.Master) " +            "|| execution(* com.ask.student.service..*.insert*(..)) " +            "|| execution(* com.ask.student.service..*.clean*(..)) " +            "|| execution(* com.ask.student.service..*.reset*(..)) " +            "|| execution(* com.ask.student.service..*.add*(..)) " +            "|| execution(* com.ask.student.service..*.update*(..)) " +            "|| execution(* com.ask.student.service..*.edit*(..)) " +            "|| execution(* com.ask.student.service..*.delete*(..)) " +            "|| execution(* com.ask.student.service..*.remove*(..))")    public void writePointcut() {    }    @Before("readPointcut()")    public void read() {        DBContextHolder.slave();    }    @Before("writePointcut()")    public void write() {        DBContextHolder.master();    }    @After("readPointcut()||writePointcut()")    public void afterSwitchDS(){        DBContextHolder.clearDB();    }}

以上最后一个方法的作用,在拦截器中获取后及时清除避免导致来回切换当前线程变量延迟问题导致某些操作的数据源错误

DBContextHolder.clearDB();

@After("readPointcut()||writePointcut()")

public void afterSwitchDS(){

DBContextHolder.clearDB();

}

2、mybatis-plus的实现方式

这个方式配置简单,代码少,很多事情mybatis-plus都已经做好了,推荐使用

yml配置如下

  datasource:    dynamic:      primary: master  #设置默认的数据源或者数据源组,默认值即为master      strict: false #设置严格模式,默认false不启动. 启动后在未匹配到指定数据源时候会抛出异常,不启动则使用默认数据源.      datasource:        master:          url: jdbc:mysql://xxx:3306/db0?useUnicode=true&characterEncoding=UTF-8&autoReconnect=true&useSSL=false&zeroDateTimeBehavior=convertToNull&serverTimezone=Asia/Shanghai          username: admin          password: 123456          driver-class-name: com.mysql.cj.jdbc.Driver          type: com.zaxxer.hikari.HikariDataSource          hikari:            minimum-idle: 5            maximum-pool-size: 15            auto-commit: true            idle-timeout: 30000            pool-name: springHikariCP            max-lifetime: 1800000            connection-timeout: 30000            connection-test-query: SELECT 1        slave1:          url: jdbc:mysql://xxx:3306/db2?useUnicode=true&characterEncoding=UTF-8&autoReconnect=true&useSSL=false&zeroDateTimeBehavior=convertToNull&serverTimezone=Asia/Shanghai          username: admin          password: 123456          driver-class-name: com.mysql.cj.jdbc.Driver          type: com.zaxxer.hikari.HikariDataSource          hikari:            minimum-idle: 5            maximum-pool-size: 15            auto-commit: true            idle-timeout: 30000            pool-name: springHikariCP            max-lifetime: 1800000            connection-timeout: 30000            connection-test-query: SELECT 1        slave2:          url: jdbc:mysql://xxx:3306/db3?useUnicode=true&characterEncoding=UTF-8&autoReconnect=true&useSSL=false&zeroDateTimeBehavior=convertToNull&serverTimezone=Asia/Shanghai          username: admin          password: 123456          driver-class-name: com.mysql.cj.jdbc.Driver          type: com.zaxxer.hikari.HikariDataSource          hikari:            minimum-idle: 5            maximum-pool-size: 15            auto-commit: true            idle-timeout: 30000            pool-name: springHikariCP            max-lifetime: 1800000            connection-timeout: 30000            connection-test-query: SELECT 1

使用起来非常简单,只需要加上这个master的注解即可

@Override    @DS("master")    public DestMedia getOneByCodeFromEpg(String code) {        QueryWrapper queryWrapper = new QueryWrapper();        queryWrapper.eq("code", code);        return super.getOne(queryWrapper);    }

上述内容就是mybatis中怎么实现读写分离,你们学到知识或技能了吗?如果还想学到更多技能或者丰富自己的知识储备,欢迎关注编程网行业资讯频道。

阅读原文内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     801人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     348人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     311人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     432人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     220人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-后端开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯