• springboot动态多数据源切换


    application-test.properties

    #datasource -- mysql
    multiple.datasource.master.url=jdbc:mysql://localhost:3306/test1?useUnicode=true&characterEncoding=utf8&autoReconnect=true&allowMultiQueries=true
    multiple.datasource.master.username=root
    multiple.datasource.master.password=pypua
    multiple.datasource.master.driverClassName=com.mysql.jdbc.Driver
    multiple.datasource.master.InitialSize=10
    multiple.datasource.master.MinIdle=10
    multiple.datasource.master.MaxActive=100
    
    multiple.datasource.slave.url=jdbc:mysql://localhost:3306/test2?useUnicode=true&characterEncoding=utf8&autoReconnect=true&allowMultiQueries=true
    multiple.datasource.slave.username=root
    multiple.datasource.slave.password=pypua
    multiple.datasource.slave.driverClassName=com.mysql.jdbc.Driver
    multiple.datasource.slave.InitialSize=10
    multiple.datasource.slave.MinIdle=10
    multiple.datasource.slave.MaxActive=100

    创建核心枚举类型 (多个数据源的名称)DataSourceKey

    package com.pupeiyuan.core;
    
    public enum DataSourceKey {
    
         DB_MASTER,
         DB_SLAVE1,
    }

    创建动态数据源DynamicRoutingDataSource,代表当前数据源

    package com.pupeiyuan.core;
    
    import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;
    
    public class DynamicRoutingDataSource extends AbstractRoutingDataSource{
    
        @Override
        protected Object determineCurrentLookupKey() {
            logger.info("当前数据源:{}"+ DynamicDataSourceContextHolder.get());
            return DynamicDataSourceContextHolder.get();
        }
    
    }

    创建动态数据源上下文取值类 DynamicDataSourceContextHolder.java

    package com.pupeiyuan.core;
    
    import org.apache.log4j.Logger;
    
    public class DynamicDataSourceContextHolder {
    
          private static final Logger LOG = Logger.getLogger(DynamicDataSourceContextHolder.class);
          private static final ThreadLocal<DataSourceKey> currentDatesource = new ThreadLocal<>();
          /**
             * 清除当前数据源
             */
            public static void clear() {
                currentDatesource.remove();
            }
    
            /**
             * 获取当前使用的数据源
             *
             * @return 当前使用数据源的ID
             */
            public static DataSourceKey get() {
                return currentDatesource.get();
            }
    
            /**
             * 设置当前使用的数据源
             *
             * @param value 需要设置的数据源ID
             */
            public static void set(DataSourceKey value) {
                currentDatesource.set(value);
            }
    
            /**
             * 设置从从库读取数据
             * 采用简单生成随机数的方式切换不同的从库
             */
            /*public static void setSlave() {
                if (RandomUtils.nextInt(0, 2) > 0) {
                    DynamicDataSourceContextHolder.set(DataSourceKey.DB_SLAVE2);
                } else {
                    DynamicDataSourceContextHolder.set(DataSourceKey.DB_SLAVE1);
                }
            }*/
    }

    最主要的配置 mybatisConfig

    package com.pupeiyuan.config;
    
    import java.sql.SQLException;
    import java.util.HashMap;
    import java.util.Map;
    import java.util.Properties;
    
    import javax.sql.DataSource;
    
    import org.apache.ibatis.session.SqlSessionFactory;
    import org.mybatis.spring.SqlSessionFactoryBean;
    import org.mybatis.spring.SqlSessionTemplate;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
    import org.springframework.boot.context.properties.ConfigurationProperties;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.core.annotation.Order;
    import org.springframework.core.io.Resource;
    import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
    import org.springframework.core.io.support.ResourcePatternResolver;
    import org.springframework.jdbc.datasource.DataSourceTransactionManager;
    import org.springframework.transaction.PlatformTransactionManager;
    
    import com.alibaba.druid.pool.DruidDataSource;
    import com.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceBuilder;
    import com.github.pagehelper.PageHelper;
    import com.pupeiyuan.core.DataSourceKey;
    import com.pupeiyuan.core.DynamicRoutingDataSource;
    
    import tk.mybatis.spring.annotation.MapperScan;
    import tk.mybatis.spring.mapper.MapperScannerConfigurer;
    
    @Configuration
    @MapperScan("com.pupeiyuan.mapper")
    public class MyBatisConfig {
          @Bean
            //此处的"multiple.datasource.master"需要你在application.properties中配置,详细信息看下面贴出的application.properties文件。
            @ConfigurationProperties(prefix = "multiple.datasource.master")
            public DataSource dbMaster() {
              DruidDataSource druidDataSource = DruidDataSourceBuilder.create().build();
              //配置监控统计拦截的filters,去掉后监控界面sql无法统计,'wall'用于防火墙
                try {
                    druidDataSource.setFilters("stat,wall,log4j");
                } catch (SQLException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            
                // 通过connectProperties属性来打开mergeSql功能;慢SQL记录
                druidDataSource.setConnectionProperties("druid.stat.mergeSql=true;druid.stat.slowSqlMillis=5000");
                //合并多个DruidDataSource的监控数据
                druidDataSource.setUseGlobalDataSourceStat(true);
                return druidDataSource;
            }
    
            @Bean
            @ConfigurationProperties(prefix = "multiple.datasource.slave")
            public DataSource dbSlave1() {
                 DruidDataSource druidDataSource = DruidDataSourceBuilder.create().build();
                  //配置监控统计拦截的filters,去掉后监控界面sql无法统计,'wall'用于防火墙
                    try {
                        druidDataSource.setFilters("stat,wall,log4j");
                    } catch (SQLException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }
                
                    // 通过connectProperties属性来打开mergeSql功能;慢SQL记录
                    druidDataSource.setConnectionProperties("druid.stat.mergeSql=true;druid.stat.slowSqlMillis=5000");
                    //合并多个DruidDataSource的监控数据
                    druidDataSource.setUseGlobalDataSourceStat(true);
                    return druidDataSource;
            }
            /**
             * 核心动态数据源
             *
             * @return 数据源实例
             */
            @Bean
            public DataSource dynamicDataSource() {
                DynamicRoutingDataSource dataSource = new DynamicRoutingDataSource();
                dataSource.setDefaultTargetDataSource(dbMaster());
                Map<Object, Object> dataSourceMap = new HashMap<>(4);
                dataSourceMap.put(DataSourceKey.DB_MASTER, dbMaster());
                dataSourceMap.put(DataSourceKey.DB_SLAVE1, dbSlave1());
                dataSource.setTargetDataSources(dataSourceMap);
                return dataSource;
            }
        
            @Bean
            public SqlSessionFactory sqlSessionFactory() throws Exception {
                SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();
                sqlSessionFactoryBean.setDataSource(dynamicDataSource());
                //此处设置为了解决找不到mapper文件的问题
                //sqlSessionFactoryBean.setMapperLocations(new PathMatchingResourcePatternResolver().getResources("classpath:mapper/*.xml"));
                return sqlSessionFactoryBean.getObject();
            }
            @Bean
            public SqlSessionTemplate sqlSessionTemplate() throws Exception {
                return new SqlSessionTemplate(sqlSessionFactory());
            }
            /**
             * 事务管理
             *
             * @return 事务管理实例
             */
            @Bean
            public PlatformTransactionManager platformTransactionManager() {
                return new DataSourceTransactionManager(dynamicDataSource());
            }
        
    }

    如果要配置自动切换数据源可以考虑AOP方式或者拦截器的方式进行配置,我这里采用手动切换

    controller中手动切换

    package com.pupeiyuan.controller;
    
    import java.util.HashMap;
    import java.util.List;
    import java.util.Map;
    
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.context.annotation.Scope;
    import org.springframework.stereotype.Controller;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RequestMethod;
    import org.springframework.web.bind.annotation.RestController;
    import org.springframework.web.servlet.ModelAndView;
    
    import com.github.pagehelper.PageHelper;
    import com.pupeiyuan.bean.NhReportStatusHistory;
    import com.pupeiyuan.common.controller.BaseController;
    import com.pupeiyuan.core.DataSourceKey;
    import com.pupeiyuan.core.DynamicDataSourceContextHolder;
    import com.pupeiyuan.services.NhReportService;
    /**
     * @author pypua
     * @date 2018年8月30日 上午9:21:20
     * 
     */
    @Controller
    @RequestMapping("burket")
    @Scope("prototype")
    public class BurketController extends BaseController {
        
        //services层注入
        @Autowired NhReportService nhReportService;
        
        @RequestMapping(value = "/burketList", method = {RequestMethod.GET,RequestMethod.POST})
        public ModelAndView burketList(HttpServletRequest request,
                HttpServletResponse response
                ) throws Exception {
            System.out.println("hello,springboot");
           //参数容器
            Map<String, Object> params = new HashMap<String, Object>();
            PageHelper.startPage(1, 2);
            DynamicDataSourceContextHolder.set(DataSourceKey.DB_SLAVE1);
            List<NhReportStatusHistory> findList = nhReportService.findList(params);
            ModelAndView modelAndView = new ModelAndView(); 
            modelAndView.setViewName("burketList");
            modelAndView.addObject("list", findList);
            return modelAndView;
        }
        
    }

    -----------------------------------------------亲测有效------------------------------------------------------

  • 相关阅读:
    初识python
    文件操作
    初识python
    pycharm IDE
    初识python
    初识Python
    python之网络编程-多线程
    python之并发编程-进程之间的通信
    python之并发编程-多进程
    python之并发编程-操作系统
  • 原文地址:https://www.cnblogs.com/pypua/p/10081387.html
Copyright © 2020-2023  润新知