本文将介绍spring boot下如何配置多数据源,持久层框架使用mybatis。附源码(开发工具idea,数据库连接池使用druid,项目管理工具maven)
目录
4.3 新建通用的基础mapper来继承mybatis的通用mapper
1、首先搭建项目double_db
下面是pom文件
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.1.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.harris</groupId>
<artifactId>double_db</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>double_db</name>
<description>Demo project for Spring Boot</description>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
</properties>
<dependencies>
<!-- druid连接池-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>1.1.6</version>
</dependency>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>1.3.2</version>
</dependency>
<dependency>
<groupId>tk.mybatis</groupId>
<artifactId>mapper-spring-boot-starter</artifactId>
<version>1.2.4</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.12</version>
</dependency>
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper-spring-boot-starter</artifactId>
<version>1.1.1</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-undertow</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<optional>true</optional>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
2、再按照以下结构配置项目目录结构:
(后续将讲解每个目录的用途)
3、配置application.properties:
(为模拟多数据源,本项目连接本地两个不同数据库进行演示)
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
4、整合mybatis的通用mapper
4.1配置数据库连接池druid
新建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;
}
}
4.2 配置mybatis的分页插件PageHelper
新建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;
}
}
4.3 新建通用的基础mapper来继承mybatis的通用mapper
新建接口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<T> extends Mapper<T>,MySqlMapper<T>,ConditionMapper<T>,RowBoundsMapper<T> {
}
后续项目的实体类只需要继承该BaseMapper即可使用通用mapper
5、配置mvc
新建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<String, Date> dateConverter(){
return new Converter<String, Date>() {
@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);
}
}
6.配置多数据源
在步骤三中我以配置了两个数据源,由于使用了多个数据源,所以无法单通过配置文件告诉程序哪个mapper要使用哪个数据源因此还需要通过配置类说明。
6.1 配置主数据源
在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);
}
}
注:
- 因为使用了多数据源,将无法从配置文件中配置mapper扫描路径,因此需要使用@MapperScan注解来扫描该数据源下的mapper
- @Bean声明实例的名称,防止多数据源注入冲突
- @Primary声明为主数据源,在多数据源下建议声明一个数据源为主数据源
- @ConfigurationProperties(prefix = "spring.datasource1")注解声明该bean对应配置文件在前缀为spring.datasource1的配置属性
6.2 配置副数据源
新建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的项目基本相当。
7、创建不同数据源的实体类
7.1创建数据库
在本地新建数据库one,添加表my_user_one,表为演示表,字段简单演示,各位可根据实际项目调整。
在本地新建数据库two,添加表my_user_two
7.2新建对应的实体类
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;
}
}
8、编写不同数据源的mapper
在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<MyUserOne> {
/**
* 1
* @return
*/
List<MyUserOne> 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<MyUserTwo> {
/**
* 2
* @return
*/
List<MyUserTwo> queryAll2();
}
9、编写mybatis映射文件
因为使用了多数据源,无法在application中配置mybatis的xml路径,所以在项目中必须将xml在resources下路径与src中mapper的路径相同。
在resources下新建com.harris.double_db.mapper路径的包,再分别新建source1、source2两个包
在source1下新建MyOneMapper.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!--
SQL Mapper xml: sql 映射文件,所有的SQL语句写在这种文件里。
mapper为根节点。namespace属性是必须的且在整个系统内是唯一的。
-->
<mapper namespace="com.harris.double_db.mapper.source1.MyOneMapper">
<!--查询-->
<select id="queryAll1" resultType="com.harris.double_db.entity.MyUserOne">
select * from my_user_one
</select>
</mapper>
在source2下新建MyTwoMapper.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!--
SQL Mapper xml: sql 映射文件,所有的SQL语句写在这种文件里。
mapper为根节点。namespace属性是必须的且在整个系统内是唯一的。
-->
<mapper namespace="com.harris.double_db.mapper.source2.MyTwoMapper">
<!--查询-->
<select id="queryAll2" resultType="com.harris.double_db.entity.MyUserTwo">
select * from my_user_two
</select>
</mapper>
10、编写service
新建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<String,Object> findAll(){
List<MyUserOne> ones = myOneMapper.queryAll1();
List<MyUserTwo> twos = myTwoMapper.queryAll2();
Map<String,Object> map=new HashMap<>(2);
map.put("one",ones);
map.put("two",twos);
return map;
}
/**
* 使用mybatis的通用mapper进行查询
* @return
*/
public Map<String,Object> findAllByBaseMapper(){
Example exampleOne = new Example(MyUserOne.class);
Example.Criteria criteriaOne = exampleOne.createCriteria();
criteriaOne.andBetween("age",10,30);
List<MyUserOne> myUserOnes = myOneMapper.selectByExample(exampleOne);
Example exampleTwo = new Example(MyUserTwo.class);
Example.Criteria criteriaTwo = exampleTwo.createCriteria();
criteriaTwo.andBetween("age",10,30);
List<MyUserTwo> myUserTwos = myTwoMapper.selectByExample(exampleTwo);
Map<String,Object> map=new HashMap<>(2);
map.put("one",myUserOnes);
map.put("two",myUserTwos);
return map;
}
}
11、编写controller
本文为方便演示,将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<String,Object> method1(){
return userService.findAll();
}
@RequestMapping(value = "/method2",method = RequestMethod.GET)
public Map<String,Object> method2(){
return userService.findAllByBaseMapper();
}
}
12、启动项目
使用浏览器进行访问,我们看到页面显示数据都两个数据源下的内容,大功告成!
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进行的查询)
13、项目源码下载路径
https://gitee.com/jie_harris/multiple-data-source.git
手编不易,转载或参考请注明链接,谢谢!
来源:CSDN
作者:昌杰的攻城狮之路
链接:https://blog.csdn.net/qq_32352777/article/details/86289724