本文将介绍spring boot下如何配置多数据源,持久层框架使用mybatis。附源码(开发工具idea,数据库连接池使用druid,项目管理工具maven)
目录
1、首先搭建项目double_db
2、再按照以下结构配置项目目录结构
3、配置application.properties
4、整合mybatis的通用mapper
4.1配置数据库连接池druid
4.2 配置mybatis的分页插件PageHelper
4.3 新建通用的基础mapper来继承mybatis的通用mapper
5、配置mvc
6、配置多数据源
6.1 配置主数据源
6.2 配置副数据源
7、创建不同数据源的实体类
7.1创建数据库
7.2新建对应的实体类
8、编写不同数据源的mapper
10、编写service
11、编写controller
12、启动项目
13、项目源码下载路径
手编不易,转载或参考请注明链接,谢谢!
下面是pom文件
4.0.0
org.springframework.boot
spring-boot-starter-parent
1.5.1.RELEASE
com.harris
double_db
0.0.1-SNAPSHOT
double_db
Demo project for Spring Boot
UTF-8
UTF-8
1.8
com.alibaba
druid-spring-boot-starter
1.1.6
org.mybatis.spring.boot
mybatis-spring-boot-starter
1.3.2
tk.mybatis
mapper-spring-boot-starter
1.2.4
mysql
mysql-connector-java
8.0.12
com.github.pagehelper
pagehelper-spring-boot-starter
1.1.1
org.springframework.boot
spring-boot-starter-undertow
org.springframework.boot
spring-boot-starter-web
org.springframework.boot
spring-boot-starter-test
test
org.springframework.boot
spring-boot-devtools
true
org.springframework.boot
spring-boot-maven-plugin
(后续将讲解每个目录的用途)
(为模拟多数据源,本项目连接本地两个不同数据库进行演示)
logging.level.com.harris.double_db.mapper = debug
spring.datasource1.driver-class-name = com.mysql.cj.jdbc.Driver
spring.datasource1.url = jdbc:mysql://localhost:3306/one?serverTimezone=UTC&userUnicode=true&characterEncoding=utf-8&&useSSL=false
spring.datasource1.username = root
spring.datasource1.password = 123456
##Druid
# 初始化大小,最小,最大
spring.datasource1.druid.initial-size=10
spring.datasource1.druid.max-active=500
spring.datasource1.druid.min-idle=5
# 配置获取连接等待超时的时间
spring.datasource1.druid.max-wait=60000
# 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒
spring.datasource1.druid.time-between-eviction-runs-millis=60000
# 配置一个连接在池中最小生存的时间,单位是毫秒
spring.datasource1.druid.min-evictable-idle-time-millis=300000
spring.datasource1.druid.validation-query=SELECT 'X' FROM DUAL
spring.datasource1.druid.test-while-idle=true
spring.datasource1.druid.test-on-borrow=false
spring.datasource1.druid.test-on-return=false
# 打开PSCache,并且指定每个连接上PSCache的大小
spring.datasource1.druid.pool-prepared-statements=true
spring.datasource1.druid.max-pool-prepared-statement-per-connection-size=20
# 配置监控统计拦截的filters,去掉后监控界面sql无法统计,'wall'用于防火墙
spring.datasource1.druid.filters=stat,wall,log4j
# 通过connectProperties属性来打开mergeSql功能;慢SQL记录
spring.datasource1.druid.connectionProperties=druid.stat.mergeSql=true;druid.stat.slowSqlMillis=5000
spring.datasource2.driver-class-name = com.mysql.cj.jdbc.Driver
spring.datasource2.url = jdbc:mysql://localhost:3306/two?serverTimezone=UTC&userUnicode=true&characterEncoding=utf-8&&useSSL=false
spring.datasource2.username = root
spring.datasource2.password = 123456
##Druid
# 初始化大小,最小,最大
spring.datasource2.druid.initial-size=10
spring.datasource2.druid.max-active=500
spring.datasource2.druid.min-idle=5
# 配置获取连接等待超时的时间
spring.datasource2.druid.max-wait=60000
# 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒
spring.datasource2.druid.time-between-eviction-runs-millis=60000
# 配置一个连接在池中最小生存的时间,单位是毫秒
spring.datasource2.druid.min-evictable-idle-time-millis=300000
spring.datasource2.druid.validation-query=SELECT 'X' FROM DUAL
spring.datasource2.druid.test-while-idle=true
spring.datasource2.druid.test-on-borrow=false
spring.datasource2.druid.test-on-return=false
# 打开PSCache,并且指定每个连接上PSCache的大小
spring.datasource2.druid.pool-prepared-statements=true
spring.datasource2.druid.max-pool-prepared-statement-per-connection-size=20
# 配置监控统计拦截的filters,去掉后监控界面sql无法统计,'wall'用于防火墙
spring.datasource2.druid.filters=stat,wall,log4j
# 通过connectProperties属性来打开mergeSql功能;慢SQL记录
spring.datasource2.druid.connectionProperties=druid.stat.mergeSql=true;druid.stat.slowSqlMillis=5000
新建DruidConfig.java
package com.harris.double_db.config;
import com.alibaba.druid.support.http.StatViewServlet;
import com.alibaba.druid.support.http.WebStatFilter;
import org.springframework.boot.autoconfigure.jdbc.DataSourceProperties;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.boot.web.servlet.ServletRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.util.Arrays;
/**
* @author HCJ
*/
@Configuration
@EnableConfigurationProperties(DataSourceProperties.class)
public class DruidConfig {
/**
* 注册一个StatViewServlet
* @return
*/
@Bean
public ServletRegistrationBean statViewServlet(){
ServletRegistrationBean servletRegistrationBean = new ServletRegistrationBean();
//添加初始化参数
servletRegistrationBean.setServlet(new StatViewServlet());
servletRegistrationBean.setUrlMappings(Arrays.asList("/druid/*"));
//白名单:
servletRegistrationBean.addInitParameter("allow","");
//IP黑名单 (存在共同时,deny优先于allow) : 如果满足deny的话提示:Sorry, you are not permitted to view this page.
servletRegistrationBean.addInitParameter("deny","");
//登录查看信息的账号密码.
servletRegistrationBean.addInitParameter("loginUsername","admin");
servletRegistrationBean.addInitParameter("loginPassword","admin");
//是否能够重置数据.
servletRegistrationBean.addInitParameter("resetEnable","true");
return servletRegistrationBean;
}
/**
* 注册一个:filterRegistrationBean
* @return
*/
@Bean
public FilterRegistrationBean druidStatFilter2(){
FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean();
filterRegistrationBean.setFilter(new WebStatFilter());
//添加过滤规则.
filterRegistrationBean.setUrlPatterns(Arrays.asList("/*"));
//添加不需要忽略的格式信息.
filterRegistrationBean.addInitParameter("exclusions","*.js,*.gif,*.jpg,*.png,*.css,*.ico,/druid/*");
return filterRegistrationBean;
}
}
新建MybatisConfig.java
package com.harris.double_db.config;
import com.github.pagehelper.PageHelper;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.util.Properties;
/**
* 注册MyBatis分页插件PageHelper
* @author HCJ
*/
@Configuration
public class MybatisConfig {
@Bean
public PageHelper pageHelper() {
PageHelper pageHelper = new PageHelper();
Properties p = new Properties();
p.setProperty("offsetAsPageNum", "true");
p.setProperty("rowBoundsWithCount", "true");
p.setProperty("reasonable", "true");
pageHelper.setProperties(p);
return pageHelper;
}
}
新建接口BaseMapper.java
package com.harris.double_db.base;
import tk.mybatis.mapper.common.ConditionMapper;
import tk.mybatis.mapper.common.Mapper;
import tk.mybatis.mapper.common.MySqlMapper;
import tk.mybatis.mapper.common.RowBoundsMapper;
/**
* @author HCJ
*/
public interface BaseMapper extends Mapper,MySqlMapper,ConditionMapper,RowBoundsMapper {
}
后续项目的实体类只需要继承该BaseMapper即可使用通用mapper
新建WebMvcConfig.java
package com.harris.double_db.config;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.convert.converter.Converter;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
import java.util.Date;
import static io.undertow.util.DateUtils.parseDate;
/**
* @author HCJ
*/
@Configuration
public class WebMvcConfig extends WebMvcConfigurerAdapter{
private final Logger logger = LoggerFactory.getLogger(WebMvcConfig.class);
static final String ORIGINS[] = new String[] { "GET", "POST", "PUT", "DELETE" };
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry){
registry.addResourceHandler("/static/**").addResourceLocations("classpath:/static/");
super.addResourceHandlers(registry);
}
@Bean
public Converter dateConverter(){
return new Converter() {
@Override
public Date convert(String s) {
return parseDate(s);
}
};
}
//解决跨域问题
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowedOrigins("*")
.allowCredentials(true)
.allowedMethods("GET", "POST", "DELETE", "PUT")
.maxAge(3600);
}
}
在步骤三中我以配置了两个数据源,由于使用了多个数据源,所以无法单通过配置文件告诉程序哪个mapper要使用哪个数据源因此还需要通过配置类说明。
在config下新建一个包dataSource用于反正多数据原的配置类
新建DataSourceOneConfig.java
package com.harris.double_db.config.dataSource;
/**
* @Author: he changjie on 2019/1/3
* @Description:
*/
import com.alibaba.druid.pool.DruidDataSource;
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.SqlSessionTemplate;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import tk.mybatis.spring.annotation.MapperScan;
import javax.sql.DataSource;
@Configuration
@MapperScan(basePackages = "com.harris.double_db.mapper.source1", sqlSessionTemplateRef = "sqlSessionTemplateOne")
public class DataSourceOneConfig {
@Bean(name = "dataSourceOne")
@ConfigurationProperties(prefix = "spring.datasource1")
@Primary //设置主数据源
public DataSource DataSourceOne(){
DruidDataSource dataSource = new DruidDataSource();
return dataSource;
}
@Bean(name = "sqlSessionFactoryOne")
@Primary
public SqlSessionFactory sqlSessionFactoryOne(@Qualifier("dataSourceOne") DataSource dataSource)throws Exception{
SqlSessionFactoryBean bean = new SqlSessionFactoryBean();
bean.setDataSource(dataSource);
return bean.getObject();
}
@Bean(name = "dataSourceTransactionManagerOne")
@Primary
public DataSourceTransactionManager dataSourceTransactionManagerOne(@Qualifier("dataSourceOne") DataSource dataSource){
return new DataSourceTransactionManager(dataSource);
}
@Bean(name = "sqlSessionTemplateOne")
@Primary
public SqlSessionTemplate sqlSessionTemplateOne(@Qualifier("sqlSessionFactoryOne") SqlSessionFactory sqlSessionFactory)throws Exception{
return new SqlSessionTemplate(sqlSessionFactory);
}
}
注:
新建DataSourceTwoConfig.java
内容与主数据源配置类基本相同,因此不再说明
package com.harris.double_db.config.dataSource;
import com.alibaba.druid.pool.DruidDataSource;
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.SqlSessionTemplate;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import tk.mybatis.spring.annotation.MapperScan;
import javax.sql.DataSource;
/**
* @author HCJ
*/
@Configuration
@MapperScan(basePackages = "com.harris.double_db.mapper.source2", sqlSessionTemplateRef = "sqlSessionTemplateTwo")
public class DataSourceTwoConfig {
@Bean(name = "dataSourceTwo")
@ConfigurationProperties(prefix = "spring.datasource2")
public DataSource DataSourceTwo() {
DruidDataSource dataSource = new DruidDataSource();
return dataSource;
}
@Bean(name = "sqlSessionFactoryTwo")
public SqlSessionFactory sqlSessionFactoryOne(@Qualifier("dataSourceTwo") DataSource dataSource) throws Exception {
SqlSessionFactoryBean bean = new SqlSessionFactoryBean();
bean.setDataSource(dataSource);
return bean.getObject();
}
@Bean(name = "dataSourceTransactionManagerTwo")
public DataSourceTransactionManager dataSourceTransactionManagerOne(@Qualifier("dataSourceTwo") DataSource dataSource) {
return new DataSourceTransactionManager(dataSource);
}
@Bean(name = "sqlSessionTemplateTwo")
public SqlSessionTemplate sqlSessionTemplateOne(@Qualifier("sqlSessionFactoryTwo") SqlSessionFactory sqlSessionFactory) throws Exception {
return new SqlSessionTemplate(sqlSessionFactory);
}
}
至此多数据源的配置已基本完工,其余内容和普通spring boot的项目基本相当。
在本地新建数据库one,添加表my_user_one,表为演示表,字段简单演示,各位可根据实际项目调整。
在本地新建数据库two,添加表my_user_two
one、two分别对应两个数据源下数据库的表
新建MyUserOne.java
package com.harris.double_db.entity;
import javax.persistence.Table;
/**
* @author HCJ
*/
@Table(name = "my_user_one")
public class MyUserOne {
private String name;
private String age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getAge() {
return age;
}
public void setAge(String age) {
this.age = age;
}
}
新建MyUserTwo.java
package com.harris.double_db.entity;
import javax.persistence.Table;
/**
* @author HCJ
*/
@Table(name = "my_user_two")
public class MyUserTwo {
private String name;
private String age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getAge() {
return age;
}
public void setAge(String age) {
this.age = age;
}
}
在mapper包下新建source1和source2两个包,用于编写不同数据源下的mapper
在mapper.source1下新建接口MyOneMapper.java
package com.harris.double_db.mapper.source1;
import com.harris.double_db.base.BaseMapper;
import com.harris.double_db.entity.MyUserOne;
import org.springframework.stereotype.Repository;
import java.util.List;
/**
* @Author: he changjie on 2019/1/3
* @Description:
*/
@Repository
public interface MyOneMapper extends BaseMapper {
/**
* 1
* @return
*/
List queryAll1();
}
在mapper.source2下新建接口MyTwoMapper.java
package com.harris.double_db.mapper.source2;
import com.harris.double_db.base.BaseMapper;
import com.harris.double_db.entity.MyUserTwo;
import org.springframework.stereotype.Repository;
import java.util.List;
/**
* @Author: he changjie on 2019/1/3
* @Description:
*/
@Repository
public interface MyTwoMapper extends BaseMapper {
/**
* 2
* @return
*/
List queryAll2();
}
9、编写mybatis映射文件
因为使用了多数据源,无法在application中配置mybatis的xml路径,所以在项目中必须将xml在resources下路径与src中mapper的路径相同。
在resources下新建com.harris.double_db.mapper路径的包,再分别新建source1、source2两个包
在source1下新建MyOneMapper.xml
在source2下新建MyTwoMapper.xml
新建UserService.java
package com.harris.double_db.services;
import com.harris.double_db.entity.MyUserOne;
import com.harris.double_db.entity.MyUserTwo;
import com.harris.double_db.mapper.source1.MyOneMapper;
import com.harris.double_db.mapper.source2.MyTwoMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import tk.mybatis.mapper.entity.Example;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* @Author: he changjie on 2019/1/3
* @Description:
*/
@Service
public class UserService {
@Autowired
MyOneMapper myOneMapper;
@Autowired
MyTwoMapper myTwoMapper;
/**
* 使用mybatis的xml进行查询
* @return
*/
public Map findAll(){
List ones = myOneMapper.queryAll1();
List twos = myTwoMapper.queryAll2();
Map map=new HashMap<>(2);
map.put("one",ones);
map.put("two",twos);
return map;
}
/**
* 使用mybatis的通用mapper进行查询
* @return
*/
public Map findAllByBaseMapper(){
Example exampleOne = new Example(MyUserOne.class);
Example.Criteria criteriaOne = exampleOne.createCriteria();
criteriaOne.andBetween("age",10,30);
List myUserOnes = myOneMapper.selectByExample(exampleOne);
Example exampleTwo = new Example(MyUserTwo.class);
Example.Criteria criteriaTwo = exampleTwo.createCriteria();
criteriaTwo.andBetween("age",10,30);
List myUserTwos = myTwoMapper.selectByExample(exampleTwo);
Map map=new HashMap<>(2);
map.put("one",myUserOnes);
map.put("two",myUserTwos);
return map;
}
}
本文为方便演示,将controller写在application中,各位小伙伴切勿模仿
package com.harris.double_db;
import com.harris.double_db.services.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import java.util.Map;
@SpringBootApplication
@RestController
public class DoubleDbApplication {
public static void main(String[] args) {
SpringApplication.run(DoubleDbApplication.class, args);
System.out.println(".................server running.................");
}
@Autowired
UserService userService;
@RequestMapping(value = "/method1",method = RequestMethod.GET)
public Map method1(){
return userService.findAll();
}
@RequestMapping(value = "/method2",method = RequestMethod.GET)
public Map method2(){
return userService.findAllByBaseMapper();
}
}
使用浏览器进行访问,我们看到页面显示数据都两个数据源下的内容,大功告成!
2019-01-11 11:12:57.639 INFO 13168 --- [ restartedMain] b.c.e.u.UndertowEmbeddedServletContainer : Undertow started on port(s) 8080 (http)
2019-01-11 11:12:57.644 INFO 13168 --- [ restartedMain] c.harris.double_db.DoubleDbApplication : Started DoubleDbApplication in 3.411 seconds (JVM running for 4.072)
.................server running.................
在浏览器输入http://localhost:8080/method1,页面显示如下图所示(使用mybatis的sql xml进行的查询)
在浏览器输入http://localhost:8080/method2,页面显示如下图所示(使用mybatis的通用mapper进行的查询)
https://gitee.com/jie_harris/multiple-data-source.git