• 基于 SpringBoot,来实现MySQL读写分离技术


    作者:Yrion

    cnblogs.com/wyq178/p/13352707.html

     

     

    /**
     * 主从配置
     *
     * @author wyq
     */
    @Configuration
    @MapperScan(basePackages = "com.wyq.mysqlreadwriteseparate.mapper", sqlSessionTemplateRef = "sqlTemplate")
    public class DataSourceConfig {
    
        /**
         * 主库
         */
        @Bean
        @ConfigurationProperties(prefix = "spring.datasource.master")
        public DataSource master() {
            return DruidDataSourceBuilder.create().build();
        }
    
        /**
         * 从库
         */
        @Bean
        @ConfigurationProperties(prefix = "spring.datasource.slave")
        public DataSource slaver() {
            return DruidDataSourceBuilder.create().build();
        }
    
    
        /**
         * 实例化数据源路由
         */
        @Bean
        public DataSourceRouter dynamicDB(@Qualifier("master") DataSource masterDataSource,
                                          @Autowired(required = false) @Qualifier("slaver") DataSource slaveDataSource) {
            DataSourceRouter dynamicDataSource = new DataSourceRouter();
            Map<Object, Object> targetDataSources = new HashMap<>();
            targetDataSources.put(DataSourceEnum.MASTER.getDataSourceName(), masterDataSource);
            if (slaveDataSource != null) {
                targetDataSources.put(DataSourceEnum.SLAVE.getDataSourceName(), slaveDataSource);
            }
            dynamicDataSource.setTargetDataSources(targetDataSources);
            dynamicDataSource.setDefaultTargetDataSource(masterDataSource);
            return dynamicDataSource;
        }
    
    
        /**
         * 配置sessionFactory
         * @param dynamicDataSource
         * @return
         * @throws Exception
         */
        @Bean
        public SqlSessionFactory sessionFactory(@Qualifier("dynamicDB") DataSource dynamicDataSource) throws Exception {
            SqlSessionFactoryBean bean = new SqlSessionFactoryBean();
            bean.setMapperLocations(
                    new PathMatchingResourcePatternResolver().getResources("classpath*:mapper/*Mapper.xml"));
            bean.setDataSource(dynamicDataSource);
            return bean.getObject();
        }
    
    
        /**
         * 创建sqlTemplate
         * @param sqlSessionFactory
         * @return
         */
        @Bean
        public SqlSessionTemplate sqlTemplate(@Qualifier("sessionFactory") SqlSessionFactory sqlSessionFactory) {
            return new SqlSessionTemplate(sqlSessionFactory);
        }
    
    
        /**
         * 事务配置
         *
         * @param dynamicDataSource
         * @return
         */
        @Bean(name = "dataSourceTx")
        public DataSourceTransactionManager dataSourceTransactionManager(@Qualifier("dynamicDB") DataSource dynamicDataSource) {
            DataSourceTransactionManager dataSourceTransactionManager = new DataSourceTransactionManager();
            dataSourceTransactionManager.setDataSource(dynamicDataSource);
            return dataSourceTransactionManager;
        }
    }

    public class DataSourceRouter extends AbstractRoutingDataSource {
    
        /**
         * 最终的determineCurrentLookupKey返回的是从DataSourceContextHolder中拿到的,因此在动态切换数据源的时候注解
         * 应该给DataSourceContextHolder设值
         *
         * @return
         */
        @Override
        protected Object determineCurrentLookupKey() {
            return DataSourceContextHolder.get();
    
        }
    }

    /**
     * 利用ThreadLocal封装的保存数据源上线的上下文context
     */
    public class DataSourceContextHolder {
    
        private static final ThreadLocal<String> context = new ThreadLocal<>();
    
        /**
         * 赋值
         *
         * @param datasourceType
         */
        public static void set(String datasourceType) {
            context.set(datasourceType);
        }
    
        /**
         * 获取值
         * @return
         */
        public static String get() {
            return context.get();
        }
    
        public static void clear() {
            context.remove();
        }
    }

    @Retention(RetentionPolicy.RUNTIME)
    @Target(ElementType.METHOD)
    @Documented
    public @interface DataSourceSwitcher {
        /**
         * 默认数据源
         * @return
         */
        DataSourceEnum value() default DataSourceEnum.MASTER;
        /**
         * 清除
         * @return
         */
        boolean clear() default true;
    
    }

    @Slf4j
    @Aspect
    @Order(value = 1)
    @Component
    public class DataSourceContextAop {
    
        @Around("@annotation(com.wyq.mysqlreadwriteseparate.annotation.DataSourceSwitcher)")
        public Object setDynamicDataSource(ProceedingJoinPoint pjp) throws Throwable {
            boolean clear = false;
            try {
                Method method = this.getMethod(pjp);
                DataSourceSwitcher dataSourceSwitcher = method.getAnnotation(DataSourceSwitcher.class);
                clear = dataSourceSwitcher.clear();
                DataSourceContextHolder.set(dataSourceSwitcher.value().getDataSourceName());
                log.info("数据源切换至:{}", dataSourceSwitcher.value().getDataSourceName());
                return pjp.proceed();
            } finally {
                if (clear) {
                    DataSourceContextHolder.clear();
                }
    
            }
        }
    
        private Method getMethod(JoinPoint pjp) {
            MethodSignature signature = (MethodSignature) pjp.getSignature();
            return signature.getMethod();
        }
    
    }

    @Service
    public class OrderService {
    
        @Resource
        private OrderMapper orderMapper;
    
    
        /**
         * 读操作
         *
         * @param orderId
         * @return
         */
        @DataSourceSwitcher(DataSourceEnum.SLAVE)
        public List<Order> getOrder(String orderId) {
            return orderMapper.listOrders(orderId);
    
        }
    
        /**
         * 写操作
         *
         * @param orderId
         * @return
         */
        @DataSourceSwitcher(DataSourceEnum.MASTER)
        public List<Order> insertOrder(Long orderId) {
            Order order = new Order();
            order.setOrderId(orderId);
            return orderMapper.saveOrder(order);
        }
    }

  • 相关阅读:
    jvm系列(二):JVM内存结构
    jvm系列(一):java类的加载机制
    配置中心选型
    抓取某一个网站整站的记录
    jvm系列(五):tomcat性能调优和性能监控(visualvm)
    网站文件系统发展&&分布式文件系统fastDFS
    spring aop
    禁止页面后退JS(兼容各浏览器)
    spring ioc
    spring帝国-开篇
  • 原文地址:https://www.cnblogs.com/it-deepinmind/p/14246476.html
Copyright © 2020-2023  润新知