文章详情

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

请输入下面的图形验证码

提交验证

短信预约提醒成功

springboot结合mysql主从来实现读写分离的方法

2023-06-14 14:18

关注

这篇文章主要介绍springboot结合mysql主从来实现读写分离的方法,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完!

1.实现的功能

    基于springboot框架,application.yml配置多个数据源,使用AOP以及AbstractRootingDataSource、ThreadLocal来实现多数据源切换,以实现读写分离。mysql的主从数据库需要进行设置数据之间的同步。

2.代码实现

    application.properties中的配置

spring.datasource.druid.master.driver-class-name=com.mysql.jdbc.Driverspring.datasource.druid.master.url=jdbc:mysql://127.0.0.1:3306/node2?useUnicode=true&characterEncoding=UTF-8&allowMultiQueries=true&autoReconnect=true&useSSL=falsespring.datasource.druid.master.username=rootspring.datasource.druid.master.password=123456  spring.datasource.druid.slave.driver-class-name=com.mysql.jdbc.Driverspring.datasource.druid.slave.url=jdbc:mysql://127.0.0.1:3306/node1?useUnicode=true&characterEncoding=UTF-8&allowMultiQueries=true&autoReconnect=true&useSSL=falsespring.datasource.druid.slave.username=rootspring.datasource.druid.slave.password=123456

写一个DataSourceConfig.java来注入两个bean

 @Bean    @ConfigurationProperties("spring.datasource.druid.master")    public DataSource masterDataSource() {        logger.info("select master data source");        return DruidDataSourceBuilder.create().build();    }     @Bean    @ConfigurationProperties("spring.datasource.druid.slave")    public DataSource slaveDataSource() {        logger.info("select slave data source");        return DruidDataSourceBuilder.create().build();    }

写一个enum来标识有哪些数据源

public enum DBTypeEnum {    MASTER, SLAVE;}

然后写一个ThreadLocal本地线程的管理类,用于设置当前线程是那一个数据源

private static final ThreadLocal<DBTypeEnum> contextHolder = new ThreadLocal<>();     private static final ThreadLocal<DBTypeEnum> contextHolder2 = ThreadLocal.withInitial(() -> DBTypeEnum.MASTER);     public static void set(DBTypeEnum dbType) {        contextHolder.set(dbType);    }     public static DBTypeEnum get() {        return contextHolder.get();    }     public static void master() {        set(DBTypeEnum.MASTER);        logger.info("切换到master数据源");    }     public static void slave() {        set(DBTypeEnum.SLAVE);        logger.info("切换到slave数据源");    }     public static void cleanAll() {        contextHolder.remove();    }

然后写一个DynamicDataSource继承AbstractRootingDataSource,重写它的determineCurrentLookupKey方法。

public class DynamicDataSource extends AbstractRoutingDataSource {    private Logger logger = LogManager.getLogger(DynamicDataSource.class);     @Override    protected Object determineCurrentLookupKey() {        logger.info("此时数据源为{}", DBContextHolder.get());        return DBContextHolder.get();    }}

最后写一个AOP来实现数据源切换

@Aspect@Order(1)@Componentpublic class DataSourceAop {     private Logger logger = LogManager.getLogger(DataSourceAop.class);     @Pointcut("(execution(* com.springboot.demo.service..*.select*(..)) " +            "|| execution(* com.springboot.demo.service..*.find*(..)) " +            "|| execution(* com.springboot.demo.service..*.get*(..)))")    public void readPointcut() {        logger.info("read only operate ,into slave db");    }     @Pointcut("execution(* com.springboot.demo.service..*.insert*(..)) " +            "|| execution(* com.springboot.demo.service..*.update*(..)) " +            "|| execution(* com.springboot.demo.service..*.delete*(..)) ")    public void writePointcut() {        logger.info("read or write operate ,into master db");    }     @Before("readPointcut()")    public void read() {        logger.info("read operate");        DBContextHolder.slave();    }     @Before("writePointcut()")    public void write() {        logger.info("write operate");        DBContextHolder.master();    }     @After("writePointcut(),readPointcut()")    public void clean() {        logger.info("dataSource cleanAll");        DBContextHolder.cleanAll();    }}

注意:这里只是使用了偷懒的方法,对于service里面的select、get、find前缀的方法都使用从库,对于insert、update和delete方法都使用主库。

可以使用注解如下来进行优化:

@Retention(RetentionPolicy.RUNTIME)@Target(ElementType.METHOD)public @interface DataSource {     @AliasFor("dataSource")    DBTypeEnum value() default DBTypeEnum.MASTER;     DBTypeEnum dataSource() default DBTypeEnum.MASTER;}

使用此注解来放入到service方法上,

@DataSource(DBTypeEnum.SLAVE)

然后AOP方法修改为:

private static final String POINT = "execution (* com.springboot.demo.service.*.*(..))";   @Around(POINT)    public Object dataSourceAround(ProceedingJoinPoint joinPoint) throws Throwable {        Object[] args = joinPoint.getArgs();        Object obj;        Object target = joinPoint.getTarget();        String methodName = joinPoint.getSignature().getName();        Class clazz = target.getClass();        Class<?>[] parameterTypes = ((MethodSignature) joinPoint.getSignature()).getMethod().getParameterTypes();        boolean isDynamicDataSourceMethod = false;        try {            Method method = clazz.getMethod(methodName, parameterTypes);            DataSources currentDataSource = null;            if (method != null && method.isAnnotationPresent(DataSource.class)) {                isDynamicDataSourceMethod = true;                currentDataSource = method.getAnnotation(DataSource.class).value();                DataSourceTypeManager.set(currentDataSource);                log.info("DataSourceInterceptor Switch DataSource To {}",currentDataSource);            }            obj = joinPoint.proceed(args);            if (isDynamicDataSourceMethod) {                log.info("DataSourceInterceptor DataSource {} proceed",currentDataSource);            }        } finally {            if (isDynamicDataSourceMethod) {                DataSourceTypeManager.reset();                log.info("DataSourceInterceptor Reset DataSource To {}",DataSourceTypeManager.get());            }        }        return obj;    }

以上是“springboot结合mysql主从来实现读写分离的方法”这篇文章的所有内容,感谢各位的阅读!希望分享的内容对大家有帮助,更多相关知识,欢迎关注编程网行业资讯频道!

阅读原文内容投诉

免责声明:

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

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

软考中级精品资料免费领

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

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

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

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

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

    难度     220人已做
    查看

相关文章

发现更多好内容

猜你喜欢

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