多数据源,很多项目都用得到,比较实用。在 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

 

posted on 2017-06-14 15:50  蛋尼  阅读(29209)  评论(5编辑  收藏  举报