spring boot + mybatis plus 动态数据源实现
参考官网文档
https://mp.baomidou.com/guide/dynamic-datasource.html#%E6%96%87%E6%A1%A3-documentation
pom引入依赖
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>dynamic-datasource-spring-boot-starter</artifactId>
<version>3.1.1</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>${mybatis.plus.version}</version>
</dependency>
配置文件配置
spring:
# 数据源 配置
datasource:
dynamic:
primary: order #设置默认的数据源或者数据源组,默认值即为master
strict: false #设置严格模式,默认false不启动. 启动后在未匹配到指定数据源时候会抛出异常,不启动则使用默认数据源.
datasource:
order: # youpin
url: jdbc:mysql://127.0.0.1:3306/order?allowMultiQueries=true&useUnicode=true&characterEncoding=UTF-8&useSSL=false&serverTimezone=Asia/Shanghai&serverTimezone=GMT%2B8
username: bizuser
password: biz*2019
driver-class-name: com.mysql.cj.jdbc.Driver # 3.2.0开始支持SPI可省略此配置
user:
url: jdbc:mysql://127.0.0.1:3306/user?allowMultiQueries=true&useUnicode=true&characterEncoding=UTF-8&useSSL=false&serverTimezone=Asia/Shanghai
username: bizuser
password: biz*2019
driver-class-name: com.mysql.cj.jdbc.Driver # 3.2.0开始支持SPI可省略此配置
service 增加注解
@DS 默认数据源可以不加次注解
/**
* <p>
* 服务实现类
* </p>
*
* @author lujia
* @since 2021-03-19
*/
@DS("user")
@Service
@Slf4j
public class MemberServiceImpl extends ServiceImpl<MemberMapper, Member> implements IMemberService {
}
整合druid数据源
- 引入依赖
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>1.1.17</version>
</dependency>
- 配置文件修改
spring:
# 数据源 配置
datasource:
dynamic:
primary: order #设置默认的数据源或者数据源组,默认值即为master
strict: false #设置严格模式,默认false不启动. 启动后在未匹配到指定数据源时候会抛出异常,不启动则使用默认数据源.
druid:
initial-size: 5
min-idle: 5
maxActive: 16
maxWait: 60000
minEvictableIdleTimeMillis: 300000
validationQuery: SELECT 1
filters: stat
datasource:
order: # youpin
url: jdbc:mysql://127.0.0.1:3306/order?allowMultiQueries=true&useUnicode=true&characterEncoding=UTF-8&useSSL=false&serverTimezone=Asia/Shanghai&serverTimezone=GMT%2B8
username: bizuser
password: biz*2019
driver-class-name: com.mysql.cj.jdbc.Driver # 3.2.0开始支持SPI可省略此配置
user:
url: jdbc:mysql://127.0.0.1:3306/user?allowMultiQueries=true&useUnicode=true&characterEncoding=UTF-8&useSSL=false&serverTimezone=Asia/Shanghai
username: bizuser
password: biz*2019
driver-class-name: com.mysql.cj.jdbc.Driver # 3.2.0开始支持SPI可省略此配置
- 排除durid 默认的数据源配置类
@SpringBootApplication(exclude = DruidDataSourceAutoConfigure.class)
读写分离
-
增加自定义mybatis配置
/** * @author lujia */ @Configuration public class MybatisPlusConfig { /** * 分页插件 */ @Bean public PaginationInterceptor paginationInterceptor() { PaginationInterceptor paginationInterceptor = new PaginationInterceptor(); paginationInterceptor.setLimit(-1); return paginationInterceptor; } @Bean public MasterSlaveAutoRoutingPlugin masterSlaveAutoRoutingPlugin(){ return new MasterSlaveAutoRoutingPlugin(); } }
-
MasterSlaveAutoRoutingPlugin 是mybatis plus自带的插件,我们可以自定义实现,注入自定义的bean,实现读写的数据源路由
/** * Copyright © 2018 organization baomidou * <pre> * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * <pre/> */ package com.baomidou.dynamic.datasource.plugin; import com.baomidou.dynamic.datasource.spring.boot.autoconfigure.DynamicDataSourceProperties; import com.baomidou.dynamic.datasource.support.DbHealthIndicator; import com.baomidou.dynamic.datasource.support.DdConstants; import com.baomidou.dynamic.datasource.toolkit.DynamicDataSourceContextHolder; import lombok.extern.slf4j.Slf4j; import org.apache.ibatis.executor.Executor; import org.apache.ibatis.mapping.MappedStatement; import org.apache.ibatis.mapping.SqlCommandType; import org.apache.ibatis.plugin.*; import org.apache.ibatis.session.ResultHandler; import org.apache.ibatis.session.RowBounds; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.util.StringUtils; import java.util.Properties; /** * Master-slave Separation Plugin with mybatis * * @author TaoYu * @since 2.5.1 */ @Intercepts({ @Signature(type = Executor.class, method = "query", args = {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class}), @Signature(type = Executor.class, method = "update", args = {MappedStatement.class, Object.class})}) @Slf4j public class MasterSlaveAutoRoutingPlugin implements Interceptor { @Autowired private DynamicDataSourceProperties properties; @Override public Object intercept(Invocation invocation) throws Throwable { Object[] args = invocation.getArgs(); MappedStatement ms = (MappedStatement) args[0]; boolean empty = true; try { empty = StringUtils.isEmpty(DynamicDataSourceContextHolder.peek()); if (empty) { DynamicDataSourceContextHolder.push(getDataSource(ms)); } return invocation.proceed(); } finally { if (empty) { DynamicDataSourceContextHolder.clear(); } } } /** * 获取动态数据源名称,重写注入 DbHealthIndicator 支持数据源健康状况判断选择 * * @param mappedStatement mybatis MappedStatement * @return 获取真实的数据源名称 */ public String getDataSource(MappedStatement mappedStatement) { String slave = DdConstants.SLAVE; if (properties.isHealth()) { /* * 根据从库健康状况,判断是否切到主库 */ boolean health = DbHealthIndicator.getDbHealth(DdConstants.SLAVE); if (!health) { health = DbHealthIndicator.getDbHealth(DdConstants.MASTER); if (health) { slave = DdConstants.MASTER; } } } return SqlCommandType.SELECT == mappedStatement.getSqlCommandType() ? slave : DdConstants.MASTER; } @Override public Object plugin(Object target) { return target instanceof Executor ? Plugin.wrap(target, this) : target; } @Override public void setProperties(Properties properties) { } }