zoukankan      html  css  js  c++  java
  • MyBatis SpringBoot2.0 数据库读写分离

    1、自定义DataSource

    import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;
    
    /**
     * @Description 动态数据源
     * AbstractRoutingDataSource(每执行一次数据库,动态获取DataSource)
     */
    public class DynamicDataSource extends AbstractRoutingDataSource {
        @Override
        protected Object determineCurrentLookupKey() {
            return DynamicDataSourceContextHolder.getDataSourceType();
        }
    }

    2、数据源切换器

    import java.util.ArrayList;
    import java.util.List;
    
    /**
     * @Description 动态数据源上下文管理
     */
    public class DynamicDataSourceContextHolder {
    
        //存放当前线程使用的数据源类型信息
        private static final ThreadLocal<Object> contextHolder = new ThreadLocal<>();
        //存放数据源id
        public static List<Object> dataSourceIds = new ArrayList<>();
        
        
        //当从库数据源大于1个时,可以配置轮询方式
        public static List<Object> slaveDataSourceKeys = new ArrayList<>();
    
    
        //设置数据源
        public static void setDataSourceType(String dataSourceType) {
                if(dataSourceIds.contains(dataSourceType)) {
                    contextHolder.set(dataSourceType);
                }
        }
    
        //获取数据源
        public static Object getDataSourceType() {
            return contextHolder.get();
        }
    
        //清除数据源
        public static void clearDataSourceType() {
            contextHolder.remove();
        }
    }

    3、代理类事物切换数据源

    import org.aspectj.lang.JoinPoint;
    import org.aspectj.lang.annotation.After;
    import org.aspectj.lang.annotation.Aspect;
    import org.aspectj.lang.annotation.Before;
    import org.springframework.core.annotation.Order;
    import org.springframework.stereotype.Component;
    import org.springframework.transaction.annotation.Transactional;
    
    /**
     * @Description 动态数据源通知
     */
    @Aspect
    @Order(-1)//保证在@Transactional之前执行
    @Component
    public class DynamicDattaSourceAspect {
    
        //改变数据源,方法上存在事物的注解,则走主库
        @Before("@annotation(transactional)")
        public void changeDataSource(JoinPoint joinPoint, Transactional transactional) {
               DynamicDataSourceContextHolder.setDataSourceType("master");
        }
    
        @After("@annotation(transactional)")
        public void clearDataSource(JoinPoint joinPoint, Transactional transactional) {
            DynamicDataSourceContextHolder.clearDataSourceType();
        }
    }

    4、数据源Bean注册器

    import java.util.HashMap;
    import java.util.Map;
    
    import javax.sql.DataSource;
    
    import org.apache.ibatis.session.SqlSessionFactory;
    import org.mybatis.spring.SqlSessionFactoryBean;
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    import org.springframework.beans.factory.annotation.Value;
    import org.springframework.boot.autoconfigure.flyway.FlywayDataSource;
    import org.springframework.boot.context.properties.ConfigurationProperties;
    import org.springframework.boot.jdbc.DataSourceBuilder;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.context.annotation.Primary;
    import org.springframework.core.io.Resource;
    import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
    import org.springframework.jdbc.datasource.DataSourceTransactionManager;
    import org.springframework.transaction.PlatformTransactionManager;
    
    import tk.mybatis.spring.annotation.MapperScan;
    
    /**
     * @Description 注册动态数据源
     * 初始化数据源和提供了执行动态切换数据源的工具类
     */
    @Configuration
    @MapperScan(basePackages="com.xxxx.*.mapper")
    public class DynamicDataSourceRegister{
        protected Logger logger = LoggerFactory.getLogger(getClass());
    
    
        @Value("${datasource.type}")
        private Class<? extends DataSource> dataSourceType;
    
    
        @Bean
        @Primary
        public SqlSessionFactory sqlSessionFactory() throws Exception {
            SqlSessionFactoryBean sessionFactory = new SqlSessionFactoryBean();
            sessionFactory.setDataSource(dynamicDataSource());
            PathMatchingResourcePatternResolver pathMatchingResourcePatternResolver = new PathMatchingResourcePatternResolver();
            sessionFactory.setMapperLocations(pathMatchingResourcePatternResolver.getResources("classpath*:mapper/*Mapper.xml"));
            Resource resource = pathMatchingResourcePatternResolver.getResource("classpath:mybatis-setting.xml");
            sessionFactory.setConfigLocation(resource);
            return sessionFactory.getObject();
        }
    
        @FlywayDataSource//指定主库为flyway的数据源
        @Bean(name = "masterDataSource")
        @ConfigurationProperties(prefix = "master.datasource")
        public DataSource masterDataSource(){
            return DataSourceBuilder.create().type(dataSourceType).build();
        }
    
        @Bean(name = "slaveDataSource")
        @ConfigurationProperties(prefix = "slave.datasource")
        public DataSource slaveDataSource(){
            return DataSourceBuilder.create().type(dataSourceType).build();
        }
    
        @Bean("dynamicDataSource")
        public DataSource dynamicDataSource() {
            DynamicDataSource dynamicRoutingDataSource = new DynamicDataSource();
            Map<Object, Object> dataSourceMap = new HashMap<>(4);
            dataSourceMap.put("master", masterDataSource());
            dataSourceMap.put("slaveDataSource", slaveDataSource());
    
            // 将 slave 数据源作为默认指定的数据源
            dynamicRoutingDataSource.setDefaultTargetDataSource(slaveDataSource());
            // 将 master 和 slave 数据源作为指定的数据源
            dynamicRoutingDataSource.setTargetDataSources(dataSourceMap);
    
            // 将数据源的 key 放到数据源上下文的 key 集合中,用于切换时判断数据源是否有效
            DynamicDataSourceContextHolder.dataSourceIds.addAll(dataSourceMap.keySet());
    
            // 将 Slave 数据源的 key 放在集合中,用于轮循
            DynamicDataSourceContextHolder.slaveDataSourceKeys.addAll(dataSourceMap.keySet());
            DynamicDataSourceContextHolder.slaveDataSourceKeys.remove("master");
            return dynamicRoutingDataSource;
        } 
        
        @Bean
        public PlatformTransactionManager transactionManager() {
            
            return new DataSourceTransactionManager(dynamicDataSource());
        }
        
    
    }

    6、资源文件配置

    #datasource master
    datasource.type=com.alibaba.druid.pool.DruidDataSource  
    #master
    master.datasource.url=jdbc:mysql://localhost:3306/haogonge_dev?useUnicode=true&characterEncoding=utf8&autoReconnect=true&useSSL=false
    master.datasource.username=root
    master.datasource.password=root
    master.datasource.driver-class-name=com.mysql.jdbc.Driver
    master.datasource.pool.initialSize=3
    master.datasource.pool.maxActive=15
    master.datasource.pool.minIdle=3
    master.datasource.pool.maxWait=60000
    master.datasource.pool.timeBetweenEvictionRunsMillis=60000
    master.datasource.pool.minEvictableIdleTimeMillis=120000
    #slave
    slave.datasource.url=jdbc:mysql://localhost:3306/haogonge_dev?useUnicode=true&characterEncoding=utf8&autoReconnect=true&useSSL=false
    slave.datasource.username=root
    slave.datasource.password=root
    slave.datasource.driver-class-name=com.mysql.jdbc.Driver
    slave.datasource.pool.initialSize=3
    slave.datasource.pool.maxActive=15
    slave.datasource.pool.minIdle=3
    slave.datasource.pool.maxWait=60000
    slave.datasource.pool.timeBetweenEvictionRunsMillis=60000
    slave.datasource.pool.minEvictableIdleTimeMillis=120000
    

      

  • 相关阅读:
    jsp课程笔记(五) PreparedStatement与Statement在使用时的区别
    如何和软件项目客户打交道
    小米的成功你学不会
    photoshop cs3 字体 即时预览
    maxQ的使用
    HTML5的明天,局部有小雨
    项目如何开始:怎样和客户一起搞定需求
    从拼死拼活开发软件项目到远程遥控管理
    HttpUnit简介
    JUnit使用方法
  • 原文地址:https://www.cnblogs.com/binz/p/10452288.html
Copyright © 2011-2022 走看看