springboot这个框架,相信现在大部分企业都是使用的该框架,但是2.0 之后与之前的版本还是有些区别。这里我们谈谈如何整合mybatisPlus多数据源
一 、首先父模块pom.xml
4.0.0
com.silankeji
framework
1.0-RELEASE
pom
framework
www.silankeji.cn
mybaitsplus
swagger
redis
commons
2.1.1.RELEASE
5.1.3.RELEASE
8.0.13
1.2.47
2.6
2.3
1.1.10
2.0.3.RELEASE
3.8.1
3.8.0
2.9.2
2.9.0
org.springframework.boot
spring-boot-dependencies
${spring.boot.version}
pom
import
com.silankeji
mybaitsplus
${project.version}
com.silankeji
swagger
${project.version}
com.silankeji
redis
${project.version}
com.silankeji
commons
${project.version}
com.alibaba
fastjson
${fastJson.version}
commons-lang
commons-lang
${common.version}
org.apache.commons
commons-lang3
${common.lang3.version}
org.springframework.boot
spring-boot-starter-web
org.springframework.boot
spring-boot-autoconfigure
org.springframework.boot
spring-boot-starter-aop
org.springframework.boot
spring-boot-starter-logging
org.springframework.boot
spring-boot-devtools
${devtool.version}
runtime
org.springframework.boot
spring-boot-starter-test
org.springframework.boot
spring-boot-configuration-processor
org.springframework
spring-core
${spring.version}
org.springframework
spring-context
${spring.version}
org.springframework
spring-beans
${spring.version}
releases
http://自己的maven私服/repository/maven-releases
snapshots
http://自己的maven私服/repository/maven-snapshots
org.apache.maven.plugins
maven-compiler-plugin
${maven.compiler.version}
1.8
UTF-8
二、mybatis模块 pom.xml引入依赖jar包
这里我是父模块管理jar包版本,此处可以自己引用相关版本
framework
com.silankeji
1.0-RELEASE
../pom.xml
4.0.0
mybaitsplus
jar
mybatisplus
http://maven.apache.org
mysql
mysql-connector-java
${mysql.version}
org.springframework.boot
spring-boot-starter-jdbc
com.baomidou
mybatis-plus-boot-starter
${mybatis.version}
org.springframework.boot
spring-boot-starter-jdbc
org.springframework.boot
spring-boot-autoconfigure
com.alibaba
druid-spring-boot-starter
${druid.version}
com.silankeji
commons
1.0-RELEASE
org.apache.maven.plugins
maven-compiler-plugin
${maven.compiler.version}
1.8
utf-8
三、定义DataSource 注解
自定义多数据源切换的注解,默认为主库
@Target({ElementType.METHOD,ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface DataSource {
String value() default "master";
}
四、配置文件
这里需要配置druid以及mybatisplus的config配置文件
MybatisPlusConfig.java
@Configuration("mybatisPlusConfig")
@MapperScan(basePackages = "com.silankeji.**.mapper", sqlSessionTemplateRef = "sqlSessionTemplate")
public class MybatisPlusConfig {
/**
* 分页插件
*/
@Bean
public PaginationInterceptor paginationInterceptor() {
PaginationInterceptor paginationInterceptor = new PaginationInterceptor();
//开启PageHelper
paginationInterceptor.setLocalPage(true);
return paginationInterceptor;
}
/**
* sql执行效率插件
* 只在dev和test环境生效
*/
@Bean
@Profile({"dev", "test"})
public PerformanceInterceptor performanceInterceptor() {
PerformanceInterceptor performanceInterceptor = new PerformanceInterceptor();
//sql执行的最大时间1秒
performanceInterceptor.setMaxTime(1000);
//是否格式化
performanceInterceptor.setFormat(true);
return performanceInterceptor;
}
@Bean("master")
@ConfigurationProperties(prefix = "spring.datasource.druid.master")
@Primary
public DataSource master() {
return DruidDataSourceBuilder.create().build();
}
/**
* 动态数据源
*/
@Bean(name = "dynamic")
public DataSource multipleDataSource(@Qualifier("master") DataSource master) {
//设置默认数据源
DynamicDataSource.getInstance().setDefaultTargetDataSource(master);
DataSourceMap.getDataSourceMap().put("master", master);
DynamicDataSource.getInstance().setTargetDataSources(DataSourceMap.getDataSourceMap());
return DynamicDataSource.getInstance();
}
@Bean(name = "transactionManager")
@Order
public DataSourceTransactionManager transactionManager(@Qualifier("dynamic") DataSource dataSource) {
DataSourceTransactionManager transactionManager = new DataSourceTransactionManager();
transactionManager.setDataSource(dataSource);
//这里进行动态数据源重新设置
DynamicDataSource.getInstance().setTargetDataSources(DataSourceMap.getDataSourceMap());
//注入resolvedDataSources中
DynamicDataSource.getInstance().afterPropertiesSet();
return transactionManager;
}
@Bean(name = "sqlSessionFactory")
public SqlSessionFactory sqlSessionFactory(@Qualifier("dynamic") DataSource dataSource) throws Exception {
MybatisSqlSessionFactoryBean sqlSessionFactory = new MybatisSqlSessionFactoryBean();
sqlSessionFactory.setDataSource(dataSource);
MybatisConfiguration configuration = new MybatisConfiguration();
configuration.setJdbcTypeForNull(JdbcType.NULL);
configuration.setMapUnderscoreToCamelCase(true);
configuration.setCacheEnabled(false);
sqlSessionFactory.setConfiguration(configuration);
sqlSessionFactory.setPlugins(new Interceptor[]{
//添加分页功能
paginationInterceptor()
});
return sqlSessionFactory.getObject();
}
@Bean(name = "sqlSessionTemplate")
public SqlSessionTemplate sqlSessionTemplate(@Qualifier(value = "sqlSessionFactory") SqlSessionFactory sqlSessionFactory) {
SqlSessionTemplate sqlSessionTemplate = new SqlSessionTemplate(sqlSessionFactory);
return sqlSessionTemplate;
}
}
DruidConfig.java
这里设置了默认用户以及密码可以取消
@Configuration
@ConditionalOnProperty(name = "druid.config.enable",havingValue = "true")
public class DruidConfig{
@Resource
private Environment environment;
private final Map paramMap = new HashMap<>(7);
@Bean
public ServletRegistrationBean startViewServlet() {
getDruidConfigProperties();
ServletRegistrationBean servletRegistrationBean = new ServletRegistrationBean(new StatViewServlet(), "/druid/*");
//Ip白名单,多个在value中用逗号隔开,不配置默认所有
servletRegistrationBean.addInitParameter("allow", paramMap.get("allow"));
//ip 黑名单,这里黑名单优先级大于白名单
servletRegistrationBean.addInitParameter("deny", paramMap.get("deny"));
//控制台管理
servletRegistrationBean.addInitParameter("loginUsername", paramMap.get("loginUsername"));
servletRegistrationBean.addInitParameter("loginPassword", paramMap.get("loginPassword"));
//是否可以点击页面的重置按钮
servletRegistrationBean.addInitParameter("resetEnable", paramMap.get("resetEnable"));
return servletRegistrationBean;
}
@Bean
public FilterRegistrationBean statFilter() {
FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean(new WebStatFilter());
//添加过滤规则
filterRegistrationBean.addUrlPatterns(paramMap.get("urlPatterns"));
//忽略过滤的格式
filterRegistrationBean.addInitParameter("exclusions", paramMap.get("exclusions"));
return filterRegistrationBean;
}
private void getDruidConfigProperties(){
if(StringUtils.isEmpty(environment.getProperty("druid.config.allow"))){
paramMap.put("allow","");
}else{
paramMap.put("allow",environment.getProperty("druid.config.allow"));
}
if(StringUtils.isEmpty(environment.getProperty("druid.config.deny"))){
paramMap.put("deny","");
}else{
paramMap.put("deny",environment.getProperty("druid.config.deny"));
}
if(StringUtils.isEmpty(environment.getProperty("druid.config.loginUsername"))){
paramMap.put("loginUsername","admin");
}else{
paramMap.put("loginUsername",environment.getProperty("druid.config.loginUsername"));
}
if(StringUtils.isEmpty(environment.getProperty("druid.config.loginPassword"))){
paramMap.put("loginPassword","admin123");
}else{
paramMap.put("loginPassword",environment.getProperty("druid.config.loginPassword"));
}
if(StringUtils.isEmpty(environment.getProperty("druid.config.resetEnable"))){
paramMap.put("resetEnable","false");
}else{
paramMap.put("resetEnable",environment.getProperty("druid.config.resetEnable"));
}
if(StringUtils.isEmpty(environment.getProperty("druid.config.urlPatterns"))){
paramMap.put("urlPatterns","/*");
}else{
paramMap.put("urlPatterns",environment.getProperty("druid.config.urlPatterns"));
}
if(StringUtils.isEmpty(environment.getProperty("druid.config.exclusions"))){
paramMap.put("exclusions","*.js,*.gif,*.jpg,*.png ,*.css,*.ico,/druid/*");
}else{
paramMap.put("exclusions",environment.getProperty("druid.config.exclusions"));
}
}
}
配置动态多数据源路由对象
DynamicDataSource.java
public class DynamicDataSource extends AbstractRoutingDataSource {
private static volatile DynamicDataSource dynamicDataSource;
private DynamicDataSource(){}
@Override
protected Object determineCurrentLookupKey() {
return DataSourceContextHolder.getDatasource();
}
/**
* 单例获取对象
* @return DynamicDataSource
*/
public static DynamicDataSource getInstance() {
if (dynamicDataSource == null) {
synchronized (DynamicDataSource.class) {
if (dynamicDataSource == null) {
dynamicDataSource = new DynamicDataSource();
}
}
}
return dynamicDataSource;
}
}
配置多数据源上下文
DataSourceContextHolder.java
public class DataSourceContextHolder {
private static final ThreadLocal CONTEXT_HOLDER = new ThreadLocal();
public static void setDataSource(String name){
CONTEXT_HOLDER.set(name);
}
public static String getDatasource(){
return CONTEXT_HOLDER.get();
}
public static void cleanDataSource(){
CONTEXT_HOLDER.remove();
}
}
配置数据源存储容器
DataSourceMap.java
public final class DataSourceMap {
/**
* 全局静态存放数据源名称Map
*/
private static final Map
五、数据源动态切面设置
切记要优先加载
DataSourceAspect.java
@Component
@Aspect
@Order(-1)
public class DataSourceAspect {
private static final Logger LOGGER = LoggerFactory.getLogger(DataSourceAspect.class);
@Pointcut("@within(com.silankeji.mybatisplus.annotations.DataSource) || @annotation(com.silankeji.mybatisplus.annotations.DataSource)")
public void pointCut(){
}
@Before("pointCut() && @annotation(dataSource)")
public void doBefore(DataSource dataSource){
LOGGER.info("选择数据源---"+dataSource.value());
DataSourceContextHolder.setDataSource(dataSource.value());
}
@After("pointCut()")
public void doAfter(){
DataSourceContextHolder.cleanDataSource();
}
}
六、客户端的使用
1.引入jar包
com.silankeji
mybaitsplus
1.0-RELEASE
com.silankeji
swagger
1.0-RELEASE
com.silankeji
commons
1.0-RELEASE
com.silankeji
redis
1.0-RELEASE
2.属性配置
#mybatisPlus 配置
mybatis-plus:
#xml 路径
mapper-locations: classpath*:mybatis/*.xml
global-config:
# 全局编码
id-type: 3
#逻辑删除
logic-delete-value: 1
#逻辑不删除
logic-not-delete-value: 0
#对应数据库字段下划线转java驼峰命名
db-column-underline: true
configuration:
# map 键值转驼峰
map-underscore-to-camel-case: true
#swagger2配置
swagger2:
enable: true
title: frameDemo
basePack: com.silankeji.demo2.controller
#druid 配置
spring:
redis:
enable: true
datasource:
druid:
#开启com.silankeji.mybatisplus 数据源配置信息
enable: true
master:
#数据源配置 wall表示防火墙
filters: stat,wall,log4j2
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://数据库地址:3306/master?useUnicode=true&characterEncoding=UTF-8&allowMutiqueries=true
username: root
password: root123
#初始线程数,最小活跃线程,最大活跃线程
initial-size: 1
min-idle: 1
max-active: 5
# 连接等待时间单位毫秒
max-wait: 60000
#配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒
time-between-eviction-runs-millis: 60000
#配置一个连接在池中最小生存的时间,单位是毫秒
min-evictable-idle-time-millis: 300000
validation-query: SELECT 1 FROM DUAL
#\u6307\u660E\u8FDE\u63A5\u662F\u5426\u88AB\u7A7A\u95F2\u8FDE\u63A5\u56DE\u6536\u5668\uFF0C\u8FDB\u884C\u6821\u9A8C\uFF0C\u6821\u9A8C\u5931\u8D25\u5219\uFF0C\u6B64\u8FDE\u63A5\u4ECE\u6C60\u4E2D\u5220\u9664
test-while-idle: true
#\u501F\u51FA\u8FDE\u63A5\u65E0\u9700\u6D4B\u8BD5
test-on-borrow: false
test-on-return: false
#打开PSCache,并且指定每个连接上PSCache的大小
pool-prepared-statements: false
#\u4E0Eoracle\u6570\u636E\u5E93\u6709\u5173
max-pool-prepared-statement-per-connection-size: 20
#\u6253\u5F00mergeSql\u529F\u80FD\uFF0C\u6162Sql\u8BB0\u5F55
connection-properties: druid.stat.mergeSql=true;druid.stat.slowSqlMillis=5000
slaver:
#\u914D\u7F6E\u76D1\u63A7\u7EDF\u8BA1\u62E6\u622A\u7684filters\uFF0Cwall\u7528\u4E8E\u9632\u706B\u5899
filters: stat,wall,log4j2
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://数据库地址:3306/slaver?useUnicode=true&characterEncoding=UTF-8&allowMutiqueries=true
username: root
password: root123
#\u521D\u59CB\u5316\u5927\u5C0F\uFF0C\u6700\u5C0F\u8FDE\u63A5\uFF0C\u6700\u5927\u8FDE\u63A5
initial-size: 1
min-idle: 1
max-active: 5
#\u83B7\u53D6\u8FDE\u63A5\u7B49\u5F85\u8D85\u65F6\u65F6\u95F4
max-wait: 60000
#\u914D\u7F6E\u95F4\u9694\u591A\u4E45\u8FDB\u884C\u4E00\u6B21\u68C0\u67E5\uFF0C\u9700\u8981\u5173\u95ED\u7684\u7A7A\u95F2\u8FDE\u63A5
time-between-eviction-runs-millis: 60000
#\u914D\u7F6E\u4E00\u4E2A\u8FDE\u63A5\u5728\u6C60\u4E2D\u7684\u6700\u5C0F\u751F\u5B58\u65F6\u95F4
min-evictable-idle-time-millis: 300000
validation-query: SELECT 1 FROM DUAL
#\u6307\u660E\u8FDE\u63A5\u662F\u5426\u88AB\u7A7A\u95F2\u8FDE\u63A5\u56DE\u6536\u5668\uFF0C\u8FDB\u884C\u6821\u9A8C\uFF0C\u6821\u9A8C\u5931\u8D25\u5219\uFF0C\u6B64\u8FDE\u63A5\u4ECE\u6C60\u4E2D\u5220\u9664
test-while-idle: true
#\u501F\u51FA\u8FDE\u63A5\u65E0\u9700\u6D4B\u8BD5
test-on-borrow: false
test-on-return: false
#\u6253\u5F00psCache \u5E76\u6307\u5B9A\u6BCF\u4E2ApsCache\u5927\u5C0F\uFF0Coracle\u4E3Atrue mysql\u4E3Afalse\uFF0C\u5206\u5E93\u5206\u8868\u8F83\u591A\u8BBE\u7F6Efalse
pool-prepared-statements: false
#\u4E0Eoracle\u6570\u636E\u5E93\u6709\u5173
max-pool-prepared-statement-per-connection-size: 20
#通过connectProperties属性来打开mergeSql功能;慢SQL记录
connection-properties: druid.stat.mergeSql=true;druid.stat.slowSqlMillis=5000
slaver1:
#数据源配置 wall表示防火墙
filters: stat,wall,log4j2
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://数据库地址:3306/slaver1?useUnicode=true&characterEncoding=UTF-8&allowMutiqueries=true
username: root
password: root123
#初始线程数,最小活跃线程,最大活跃线程
initial-size: 1
min-idle: 1
max-active: 5
# 连接等待时间单位毫秒
max-wait: 60000
#配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒
time-between-eviction-runs-millis: 60000
#配置一个连接在池中最小生存的时间,单位是毫秒
min-evictable-idle-time-millis: 300000
validation-query: SELECT 1 FROM DUAL
#\u6307\u660E\u8FDE\u63A5\u662F\u5426\u88AB\u7A7A\u95F2\u8FDE\u63A5\u56DE\u6536\u5668\uFF0C\u8FDB\u884C\u6821\u9A8C\uFF0C\u6821\u9A8C\u5931\u8D25\u5219\uFF0C\u6B64\u8FDE\u63A5\u4ECE\u6C60\u4E2D\u5220\u9664
test-while-idle: true
#\u501F\u51FA\u8FDE\u63A5\u65E0\u9700\u6D4B\u8BD5
test-on-borrow: false
test-on-return: false
#打开PSCache,并且指定每个连接上PSCache的大小
pool-prepared-statements: false
#\u4E0Eoracle\u6570\u636E\u5E93\u6709\u5173
max-pool-prepared-statement-per-connection-size: 20
#\u6253\u5F00mergeSql\u529F\u80FD\uFF0C\u6162Sql\u8BB0\u5F55
connection-properties: druid.stat.mergeSql=true;druid.stat.slowSqlMillis=5000
#druid页面配置
druid:
config:
#是否开启druid监控com.silankeji.mybatisplus
enable: true
#白名单 默认所有可访问
allow: 127.0.0.1
#黑名单 默认为空
deny: 118.25.23.12
#账号 默认admin
loginUsername: root
#密码 默认admin123
loginPassword: root123
#是否允许点击页面的重置按钮,默认false
resetEnable: false
#过滤url 默认 /*
urlPatterns: /*
#不过滤的资源,注意*打头必须加双引号,下面值为默认值
exclusions: "*.js,*.gif,*.jpg,*.png ,*.css,*.ico,/druid/*"
- 动态数据源配置
MultiDataSource.java
@Configuration
public class MultiDataSource{
@Bean("slaver")
@ConfigurationProperties(prefix = "spring.datasource.druid.slaver")
public DataSource slaver() {
//创建数据源
DataSource dataSource = DruidDataSourceBuilder.create().build();
//将数据源放入动态池
DataSourceMap.setDataSourceBeanName("slaver",dataSource);
return dataSource;
}
@Bean("zzz")
@ConfigurationProperties(prefix = "spring.datasource.druid.slaver1")
public DataSource slaver1() {
//创建数据源
DataSource dataSource = DruidDataSourceBuilder.create().build();
//将数据源放入动态池
DataSourceMap.setDataSourceBeanName("zzz",dataSource);
return dataSource;
}
}
4.代码中使用,这里有3个数据源只需要使用注解@DataSource就可以使用不同的数据源
@RestController
@Api(value = "操作员工相关相信Controller")
public class EmployeeController {
private static final Logger LOG = LoggerFactory.getLogger(EmployeeController.class);
@Resource
private EmployeeService employeeService;
@RequestMapping(value = "/queryEmployee/{empNo}",method=RequestMethod.POST)
@ApiOperation(value = "获取员工信息",notes = "根据员工编号查询员工相关信息",httpMethod = "POST",produces = "application/json")
@ApiImplicitParam(name = "empNo",value = "员工编号如:1,2...",required = true,dataType="string",paramType = "path")
@DataSource
public BaseResponse getEmployeeInfo(@PathVariable(name = "empNo") String employeeNumber){
LOG.info("begin query employee info by employeeNumber:{}",employeeNumber);
EntityWrapper wrapper = new EntityWrapper<>();
wrapper.eq("employeeNumber",employeeNumber);
BaseResponse response = new BaseResponse();
response.setResult(employeeService.selectOne(wrapper));
LOG.info("query employee info is{}",JSON.toJSONString(response));
return response;
}
@RequestMapping(value = "/addEmployee",method = RequestMethod.POST)
@ApiOperation(value = "添加员工信息",notes ="增加员工相关信息",httpMethod = "POST",produces = "application/json",consumes = "application/json")
@DataSource("zzz")
public BaseResponse addEmployeeInfo(@RequestBody @ApiParam(name = "employee",value = "员工信息类") Employee employee){
LOG.info("begin add employee info:{}",JSON.toJSONString(employee));
BaseResponse response = new BaseResponse();
response.setResult(employeeService.insert(employee));
LOG.info("add employee info is {}",JSON.toJSONString(response));
return response;
}
@RequestMapping(value = "/modifyEmployee",method = RequestMethod.POST)
@ApiOperation(value = "修改员工信息",notes ="编辑员工相关信息",httpMethod = "POST",produces = "application/json",consumes = "application/json")
@DataSource("slaver")
public BaseResponse modifyEmployeeInfo(@RequestBody @ApiParam(name = "employee",value = "员工信息类") Employee employee){
LOG.info("begin update employee info:{}",JSON.toJSONString(employee));
BaseResponse response = new BaseResponse();
response.setResult(employeeService.update(employee,new EntityWrapper().eq("employeeNumber",employee.getEmployeeNumber())));
LOG.info("update employee info is {}",JSON.toJSONString(response));
return response;
}
}