zoukankan      html  css  js  c++  java
  • Springboot + Mybatis 多数据源配置

    多数据源,很多项目都用得到,比较实用。在 DEMO: springboot 与 freemarker 集成 基础上进行修改。

    修改后的项目结构大致这样:

    1、src/main/resources/application.properties 中配置好多个数据源

    datasource.jdbc.driverClassName = com.mysql.jdbc.Driver
    datasource.jdbc.url = jdbc:mysql://127.0.0.1:3306/test
    datasource.jdbc.username = root
    datasource.jdbc.password = test
    # function
    datasource.jdbc.url_stg = jdbc:mysql://10.199.xx.35:3306/test
    datasource.jdbc.username_stg = root
    datasource.jdbc.password_stg = test
    
    
    # mybatis #
    mybatis.typeAliasesPackage=demo.springboot.model 
    mybatis.mapperLocations=classpath:/mybatis/mapper/*.xml
    View Code

    2、定义一个枚举类型 DatabaseType.java,表示不同的环境

    package demo.springboot.enums;
    
    /**
     * @author meng.geng
     * function  功能环境
     * regression 回归环境
     * 
     * */
    public enum DatabaseType {
        function("function", "1"), 
        regression("regression", "2");
    
        DatabaseType(String name, String value){
            this.name = name;
            this.value = value;
        }
        
        private String name;
        private String value;
        
        public String getName(){
            return name;
        }
        
        public String getValue(){
            return value;
        }    
    }
    View Code

    3、定义一个 DatabaseContextHolder.java, 保存一个线程安全的DatabaseType容器

    package demo.springboot.conf;
    
    import demo.springboot.enums.DatabaseType;
    
    /**
     * @author danny.yao
     * 作用:保存一个线程安全的DatabaseType容器
     * 
     **/
    public class DatabaseContextHolder {
        private static final ThreadLocal<DatabaseType> contextHolder = new ThreadLocal<>();
        
        public static void setDatabaseType(DatabaseType type){
            contextHolder.set(type);
        }
        
        public static DatabaseType getDatabaseType(){
            return contextHolder.get();
        }    
    }
    View Code

    4、定义动态数据源获取的方法 DynamicDataSource.java,集成 AbstractRoutingDataSource

    package demo.springboot.conf;
    
    import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;
    
    /**
     * @author danny.yao
     * 动态数据源(需要继承AbstractRoutingDataSource)
     * 作用:使用DatabaseContextHolder获取当前线程的DatabaseType
     * 
     * */
    public class DynamicDataSource extends AbstractRoutingDataSource {
        
         protected Object determineCurrentLookupKey() {
                return DatabaseContextHolder.getDatabaseType();
            }    
    }
    View Code

    5、mybatis多数据源的配置 MybatisConfig.java

    package demo.springboot.conf;
    
    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.mybatis.spring.annotation.MapperScan;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.beans.factory.annotation.Qualifier;
    import org.springframework.beans.factory.annotation.Value;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.context.annotation.Primary;
    import org.springframework.core.env.Environment;
    import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
    
    import com.alibaba.druid.pool.DruidDataSource;
    
    import demo.springboot.enums.DatabaseType;
    
    /**
     * 
     * @author danny.yao
     * springboot集成mybatis基本入口
     * 1、创建数据源
     * 2、创建SqlSessionFactory
     */
    @Configuration
    @MapperScan(basePackages="demo.springboot.mapper", sqlSessionFactoryRef="sessionFactory")
    public class MybatisConfig {
        
        @Autowired
        Environment environment;
        
        @Value("${datasource.jdbc.driverClassName}")
        private String dbDriver;
        
        @Value("${datasource.jdbc.url}")
        private String dbUrl;
        
        @Value("${datasource.jdbc.username}")
        private String dbUsername;
        
        @Value("${datasource.jdbc.password}")
        private String dbPassword;
        
        @Value("${datasource.jdbc.url_stg}")
        private String dbUrl_stg;
        
        @Value("${datasource.jdbc.username_stg}")
        private String dbUsername_stg;
        
        @Value("${datasource.jdbc.password_stg}")
        private String dbPassword_stg;
        
        
        /**
         * 创建 local环境 dataSource
         * @throws Exception 
         */
        @Bean(name="dataSourceFunctional")
        public DataSource dataSourceLocal() throws Exception{            
            DruidDataSource dataSource = new DruidDataSource();
            dataSource.setDriverClassName(dbDriver);
            dataSource.setUrl(dbUrl);
            dataSource.setUsername(dbUsername);
            dataSource.setPassword(dbPassword);
            
            return dataSource;
        }
        
        /**
         * 创建 回归环境 dataSource
         * @throws Exception 
         */
        @Bean(name="dataSourceRegression")
        public DataSource dataSourceStaging() throws Exception{
            DruidDataSource dataSource = new DruidDataSource();
            dataSource.setDriverClassName(dbDriver);
            dataSource.setUrl(dbUrl_stg);
            dataSource.setUsername(dbUsername_stg);
            dataSource.setPassword(dbPassword_stg);
            
            return dataSource;
        }
        
        /**
         * 1、创建动态数据源
         * @throws Exception 
         * @Primary该注解表示在同一个接口有多个类可以注入的时候,默认选择哪个,而不是让@Autowired报错
         */
        @Bean(name="dynamicDataSource")
        @Primary
        public DynamicDataSource DataSource(@Qualifier("dataSourceFunctional") DataSource dataSourceFunctional, 
                                            @Qualifier("dataSourceRegression") DataSource dataSourceRegression){
            Map<Object, Object> targetDataSource = new HashMap<>();
            targetDataSource.put(DatabaseType.function, dataSourceFunctional);
            targetDataSource.put(DatabaseType.regression, dataSourceRegression);
            DynamicDataSource dataSource = new DynamicDataSource();
            dataSource.setTargetDataSources(targetDataSource);
            dataSource.setDefaultTargetDataSource(dataSourceFunctional);
            
            return dataSource;
        }
        
        /**
         * 2、根据数据源创建SqlSessionFactory
         * @throws Exception 
         */
        @Bean(name="sessionFactory")
        public SqlSessionFactory sessionFactory(@Qualifier("dynamicDataSource")DynamicDataSource dataSource) throws Exception{
            SqlSessionFactoryBean sessionFactoryBean = new SqlSessionFactoryBean();
            sessionFactoryBean.setDataSource(dataSource);
            PathMatchingResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
            sessionFactoryBean.setMapperLocations(resolver.getResources(environment.getProperty("mybatis.mapperLocations")));    //*Mapper.xml位置
            return sessionFactoryBean.getObject();
        }
    }
    View Code

    6、修改服务类 StudentService.java:添加环境切换方法setDataSourceByEnvironment,同时在获取数据的方法中切换数据源

    package demo.springboot.service;
    
    import java.util.ArrayList;
    import java.util.List;
    
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Service;
    
    import demo.springboot.conf.DatabaseContextHolder;
    import demo.springboot.enums.DatabaseType;
    import demo.springboot.mapper.StudentMapper;
    import demo.springboot.model.Student;
    
    @Service
    public class StudentService {
        
        @Autowired
        private StudentMapper studentMapper;
        
        public void setDataSourceByEnvironment(String environment){
            if (environment.equals(DatabaseType.function.getValue())){
                DatabaseContextHolder.setDatabaseType(DatabaseType.function);
            }
            if (environment.equals(DatabaseType.regression.getValue())){
                DatabaseContextHolder.setDatabaseType(DatabaseType.regression);
            }
        }
        
        public List<Student> listStudents(String environment){
            setDataSourceByEnvironment(environment);
            List<Student> students = new ArrayList<>();
            students = studentMapper.listStudents();
            return students;
        }
    
    }
    View Code

    7、修改controller类 StudentController.java : 请求需要带上环境参数 @RequestParam(value="environment", required=true)String environment

    package demo.springboot.controller;
    
    import java.util.ArrayList;
    import java.util.List;
    import java.util.Map;
    
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Controller;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RequestParam;
    
    import demo.springboot.model.Student;
    import demo.springboot.service.StudentService;
    
    @Controller
    @RequestMapping("/student")
    public class StudentController {
    
        private static final Logger LOGGER =  LoggerFactory.getLogger(StudentController.class);
        
        @Autowired
        private StudentService studentService;
        
        @RequestMapping("/list")
        public String listStudent(@RequestParam(value="environment", required=true)String environment, Map<String, Object> map){
            List<Student> students = new ArrayList<>();
            students = studentService.listStudents(environment);
            
            for (Student student : students){
                LOGGER.info(student.getId() + " - " + student.getName() + " - " + student.getNo() + " - " + student.getSex());
            }
            
            map.put("students", students);
            
            return "student";
        }    
    }
    View Code

    8、测试

    1)请求环境1的数据:http://localhost:8080/student/list?environment=1

    2)请求环境2的数据:http://localhost:8080/student/list?environment=2

  • 相关阅读:
    Android 颜色配置表-颜色类
    Android模拟器——Genymotion
    Android-adb shell 读取手机系统文件
    android webview js交互 第一节 (java和js交互)
    Android源码目录结构详解(转载)
    BlockingQueue深入分析(转)
    RUDP之三 —— Virtual Connection over UDP
    RUDP之二 —— Sending and Receiving Packets
    OSS层基础:平台区分
    RUDP之一 —— UDP VS TCP
  • 原文地址:https://www.cnblogs.com/dannyyao/p/7009264.html
Copyright © 2011-2022 走看看