多数据源,很多项目都用得到,比较实用。在 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
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; } }
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(); } }
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(); } }
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(); } }
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; } }
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"; } }
8、测试
1)请求环境1的数据:http://localhost:8080/student/list?environment=1
2)请求环境2的数据:http://localhost:8080/student/list?environment=2
---
开心工作,认真生活;回望来时路,脚印三两,笑声无数...
开心工作,认真生活;回望来时路,脚印三两,笑声无数...