• Spring动态切换数据源


    11

    //定义数据源枚举
    public enum DataSourceKey { master, slave, }

    22

    /**
     * 数据源路由
     */
    @Slf4j
    public class DynamicRoutingDataSource  extends AbstractRoutingDataSource {
        @Override
        protected Object determineCurrentLookupKey() {
            log.error("Current DataSource is [{}]", DynamicDataSourceContextHolder.getDataSourceKey());
            return DynamicDataSourceContextHolder.getDataSourceKey();
        }
    
    }
    /**
     * 数据源路由holder
     */
    @Slf4j
    public class DynamicDataSourceContextHolder {
        private static int counter = 0;
    
    
        private static final ThreadLocal<String> CONTEXT_HOLDER = ThreadLocal.withInitial(DataSourceKey.master::name);
    
        /**
         * 所有数据源key
         */
        public static List<Object> dataSourceKeys = new ArrayList<>();
    
        /**
         * 从数据源key
         */
        public static List<Object> slaveDataSourceKeys = new ArrayList<>();
    
        /**
         *
         * set数据源
         */
        public static void setDataSourceKey(String key) {
            CONTEXT_HOLDER.set(key);
        }
    
        /**
         * get数据源
         */
        public static String getDataSourceKey() {
            return CONTEXT_HOLDER.get();
        }
        /**
         * 主数据源
         */
        public static void useMasterDataSource() {
            CONTEXT_HOLDER.set(DataSourceKey.master.name());
        }
    
        /**
         * 从数据源
         */
        public static void useSlaveDataSource() {
            try {
                int datasourceKeyIndex = counter % slaveDataSourceKeys.size();//负载均衡-轮询
                CONTEXT_HOLDER.set(String.valueOf(slaveDataSourceKeys.get(datasourceKeyIndex)));
                counter++;
            } catch (Exception e) {
                log.error("Switch slave datasource failed, error message is {}", e.getMessage());
                useMasterDataSource();
                e.printStackTrace();
            }
        }
    
        public static void clearDataSourceKey() {
            CONTEXT_HOLDER.remove();
        }
    
        public static boolean containDataSourceKey(String key) {
            return dataSourceKeys.contains(key);
        }
    
    }

    33

    @Configuration
    @MapperScan(basePackages = "com.buyi.mytransaction.dao.one", sqlSessionFactoryRef = "mybatisSqlSessionFactoryOne")
    public class MyDynamicMybatisDataSource {
    
        @Bean(name = "master")
        @Primary
        @ConfigurationProperties(prefix = "spring.datasource.one.master", ignoreInvalidFields = true)
        public DataSource master() {
            return new DruidDataSource();
        }
    
        @Bean(name = "slave")
        @ConfigurationProperties(prefix = "spring.datasource.one.slave", ignoreInvalidFields = true)
        public DataSource slave() {
            return new DruidDataSource();
        }
    
        @Bean("dynamicDataSource")
        public DataSource dynamicDataSource() {
            DynamicRoutingDataSource dynamicRoutingDataSource = new DynamicRoutingDataSource();
            Map<Object, Object> dataSourceMap = new HashMap<>(4);
            dataSourceMap.put(DataSourceKey.master.name(), master());
            dataSourceMap.put(DataSourceKey.slave.name(), slave());
    
            dynamicRoutingDataSource.setDefaultTargetDataSource(master());//默认数据源
            dynamicRoutingDataSource.setTargetDataSources(dataSourceMap);//数据源
    
            DynamicDataSourceContextHolder.dataSourceKeys.addAll(dataSourceMap.keySet());//所有数据源
            DynamicDataSourceContextHolder.slaveDataSourceKeys.addAll(dataSourceMap.keySet());//设置从数据源
            DynamicDataSourceContextHolder.slaveDataSourceKeys.remove(DataSourceKey.master.name());
            return dynamicRoutingDataSource;
        }
    
        //事务管理器
        @Bean(name = "mybatisTransactionManagerOne")
        @Primary
        public DataSourceTransactionManager mybatisTransactionManager(@Qualifier("dynamicDataSource") DataSource dataSource) throws Exception {
            return new DataSourceTransactionManager(dataSource);
        }
    
        //会话工厂
        @Bean("mybatisSqlSessionFactoryOne")
        @Primary
        public SqlSessionFactory mybatisSqlSessionFactory(@Qualifier("dynamicDataSource") DataSource dataSource) throws Exception {
            SqlSessionFactoryBean sf = new SqlSessionFactoryBean();
            sf.setDataSource(dataSource);
            sf.setMapperLocations(new PathMatchingResourcePatternResolver().getResources("classpath:repository/one/**/*Mapper.xml"));
    
            //自动转驼峰   resultType="***"
            org.apache.ibatis.session.Configuration configuration = new org.apache.ibatis.session.Configuration();
            configuration.setMapUnderscoreToCamelCase(true);
            sf.setConfiguration(configuration);
            return sf.getObject();
        }
    
    }

    44

    @Slf4j
    @Aspect
    @Component
    public class DynamicDataSourceAspect {
    
        private final String[] QUERY_PREFIX = {"select","query"};
    
    
        @Pointcut("execution( * com.buyi.mytransaction.dao.one.*.*(..))")
        public void daoAspect() {
        }
    
        /**
         * 切换数据源
         */
        @Before("daoAspect()")
        public void switchDataSource(JoinPoint point) {
            Boolean isQueryMethod = isQueryMethod(point.getSignature().getName());
            if (isQueryMethod) {
                DynamicDataSourceContextHolder.useSlaveDataSource();
                log.debug("Switch DataSource to [{}] in Method [{}]",
                        DynamicDataSourceContextHolder.getDataSourceKey(), point.getSignature());
            }
        }
    
        /**
         * 重置数据源
         */
        @After("daoAspect())")
        public void restoreDataSource(JoinPoint point) {
            DynamicDataSourceContextHolder.clearDataSourceKey();
            log.debug("Restore DataSource to [{}] in Method [{}]",
                    DynamicDataSourceContextHolder.getDataSourceKey(), point.getSignature());
        }
    
    
        private Boolean isQueryMethod(String methodName) {
            for (String prefix : QUERY_PREFIX) {
                if (methodName.startsWith(prefix)) {
                    return true;
                }
            }
            return false;
        }
    }
        @Test
        //测试切换数据源
        public void test3() {
            Company c = Company.builder().companyId("789").companyName("百度").memo("人工智能").build();
            oneCompanyservice.oneInsert(c);
    
            List<Company> companyList = oneCompanyservice.selectAll();
            for (Company company : companyList) {
                System.out.println(company);
                //Company(companyId=999, companyName=百度子公司, memo=111)
    //此条数据在从数据库中已存在 } }
  • 相关阅读:
    自己实现的string的库函数
    单链表的面试题
    顺序表的实现
    指针数组与数组指针
    指针与数组
    sizeof 与 strlen
    HTML配色工具!在线配色工具
    [转载] python的sorted函数对字典按key排序和按value排序
    [转载]python脚本删除一定时间以外的文件
    python基础教程(四)
  • 原文地址:https://www.cnblogs.com/dyg0826/p/10763883.html
Copyright © 2020-2023  润新知