由于服务没有做微服务部署,需要在后台管理系统访问其他服务的库,所以需要用到动态数据源切换
引入依赖
mybatis-plus动态数据源依赖
<dependency><groupId>com.baomidou</groupId><artifactId>dynamic-datasource-spring-boot-starter</artifactId><version>3.5.1</version></dependency>
更改配置
spring:application:name: appNamedatasource:dynamic:# 指定默认数据源primary: aaaa1strict: falsedatasource:# 配置第一个数据源aaaa1:driverClassName: com.mysql.cj.jdbc.Driverurl: jdbc:mysql://host:3306/xxx?characterEncoding=utf8&connectTimeout=1000&socketTimeout=3000&autoReconnect=true&useUnicode=true&useSSL=false&serverTimezone=Asia/Shanghai&rewriteBatchedStatements=trueusername: usernamepassword: password# 配置第二个数据源 aaaa2:driverClassName: com.mysql.cj.jdbc.Driverurl: jdbc:mysql://host:3306/xxx?characterEncoding=utf8&connectTimeout=1000&socketTimeout=3000&autoReconnect=true&useUnicode=true&useSSL=false&serverTimezone=Asia/Shanghai&rewriteBatchedStatements=trueusername: usernamepassword: passworddruid:# 初始连接数initialSize: 5# 最小连接池数量minIdle: 10# 最大连接池数量maxActive: 20# 配置获取连接等待超时的时间maxWait: 60000# 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒timeBetweenEvictionRunsMillis: 60000# 配置一个连接在池中最小生存的时间,单位是毫秒minEvictableIdleTimeMillis: 300000# 配置一个连接在池中最大生存的时间,单位是毫秒maxEvictableIdleTimeMillis: 900000# 配置检测连接是否有效validationQuery: SELECT 1 FROM DUALtestWhileIdle: truetestOnBorrow: falsetestOnReturn: falsewebStatFilter:enabled: truestatViewServlet:enabled: true# 设置白名单,不填则允许所有访问allow:url-pattern: /druid/*# 控制台管理用户名和密码# login-username: login-username# login-password: login-passwordfilter:stat:enabled: true# 慢SQL记录log-slow-sql: trueslow-sql-millis: 1000merge-sql: truewall:config:multi-statement-allow: true
配置类
package com.ruoyi.framework.config;import com.baomidou.mybatisplus.extension.spring.MybatisSqlSessionFactoryBean;
import com.ruoyi.common.utils.StringUtils;
import org.apache.ibatis.io.VFS;
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.boot.autoconfigure.SpringBootVFS;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.env.Environment;
import org.springframework.core.io.DefaultResourceLoader;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.core.io.support.ResourcePatternResolver;
import org.springframework.core.type.classreading.CachingMetadataReaderFactory;
import org.springframework.core.type.classreading.MetadataReader;
import org.springframework.core.type.classreading.MetadataReaderFactory;
import org.springframework.util.ClassUtils;import javax.sql.DataSource;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;/*** Mybatis支持*匹配扫描包** @author ruoyi*/
@Configuration
public class MyBatisConfig {@Autowiredprivate Environment env;static final String DEFAULT_RESOURCE_PATTERN = "**/*.class";public static String setTypeAliasesPackage(String typeAliasesPackage) {ResourcePatternResolver resolver = (ResourcePatternResolver) new PathMatchingResourcePatternResolver();MetadataReaderFactory metadataReaderFactory = new CachingMetadataReaderFactory(resolver);List<String> allResult = new ArrayList<String>();try {for (String aliasesPackage : typeAliasesPackage.split(",")) {List<String> result = new ArrayList<String>();aliasesPackage = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX+ ClassUtils.convertClassNameToResourcePath(aliasesPackage.trim()) + "/" + DEFAULT_RESOURCE_PATTERN;Resource[] resources = resolver.getResources(aliasesPackage);if (resources != null && resources.length > 0) {MetadataReader metadataReader = null;for (Resource resource : resources) {if (resource.isReadable()) {metadataReader = metadataReaderFactory.getMetadataReader(resource);try {result.add(Class.forName(metadataReader.getClassMetadata().getClassName()).getPackage().getName());} catch (ClassNotFoundException e) {e.printStackTrace();}}}}if (result.size() > 0) {HashSet<String> hashResult = new HashSet<String>(result);allResult.addAll(hashResult);}}if (allResult.size() > 0) {typeAliasesPackage = String.join(",", (String[]) allResult.toArray(new String[0]));} else {throw new RuntimeException("mybatis typeAliasesPackage 路径扫描错误,参数typeAliasesPackage:" + typeAliasesPackage + "未找到任何包");}} catch (IOException e) {e.printStackTrace();}return typeAliasesPackage;}public Resource[] resolveMapperLocations(String[] mapperLocations) {ResourcePatternResolver resourceResolver = new PathMatchingResourcePatternResolver();List<Resource> resources = new ArrayList<Resource>();if (mapperLocations != null) {for (String mapperLocation : mapperLocations) {try {Resource[] mappers = resourceResolver.getResources(mapperLocation);resources.addAll(Arrays.asList(mappers));} catch (IOException e) {// ignore}}}return resources.toArray(new Resource[resources.size()]);}@Beanpublic SqlSessionFactory sqlSessionFactory(DataSource dataSource) throws Exception {String typeAliasesPackage = env.getProperty("mybatis.typeAliasesPackage");String mapperLocations = env.getProperty("mybatis.mapperLocations");String configLocation = env.getProperty("mybatis.configLocation");typeAliasesPackage = setTypeAliasesPackage(typeAliasesPackage);VFS.addImplClass(SpringBootVFS.class);// 注意这里使用的是MybatisSqlSessionFactoryBean而不是SqlSessionFactoryBeanfinal MybatisSqlSessionFactoryBean sessionFactory = new MybatisSqlSessionFactoryBean();sessionFactory.setDataSource(dataSource);sessionFactory.setTypeAliasesPackage(typeAliasesPackage);sessionFactory.setMapperLocations(resolveMapperLocations(StringUtils.split(mapperLocations, ",")));sessionFactory.setConfigLocation(new DefaultResourceLoader().getResource(configLocation));sessionFactory.setPlugins(new MybatisSqlLoggerInterceptor());return sessionFactory.getObject();}
}
添加注解
@DS注解我一般放在dao层,因为觉得这样更合理,如果使用了BaseMapper的批量处理以及接口操作,可以将注解放在service层解决找不到数据库问题
启动测试
问题:
动态数据源切换时效
当服务层接口添加事务注解,动态数据源切换就会失效,并且会使用默认的主数据源
批量处理接口异常
当dao层具体实现继承了BaseMapper并且服务处使用IService去实现,在批量处理时候就会出现异常,此时可以通过更改配置解决
使用 MybatisSqlSessionFactoryBean 替换 SqlSessionFactoryBean
参开原文:mybatis-plus框架TABLE_INFO_CACHE获取不到对应的TableInfo对象_error: can not execute. because can not find cache-CSDN博客
另一种方式实现(未测试):https://www.cnblogs.com/zhaww/p/12706941.html
根据Mybatis-plus配置动态数据源-从数据库获取源_mybatis plus 拦截器怎么获取当前数据库类型-CSDN博客
工作笔记,持续更新完善中