赞
踩
<!-- 动态切换数据源 -->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>dynamic-datasource-spring-boot-starter</artifactId>
<version>3.5.1</version>
</dependency>
spring: datasource: dynamic: primary: master #设置默认的数据源或者数据源组,默认值即为master strict: false #设置严格模式,默认false不启动. 启动后在未匹配到指定数据源时候回抛出异常,不启动会使用默认数据源. datasource: # 主库数据源 master: url: username: password: driver-class-name: com.mysql.cj.jdbc.Driver # 从库数据源 # slave: # # 从数据源开关/默认关闭 # enabled: false # url: # username: # password:
如果想整合druid连接池,可做如下配置
spring: autoconfigure: exclude: com.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceAutoConfigure datasource: dynamic: primary: master #设置默认的数据源或者数据源组,默认值即为master strict: false #设置严格模式,默认false不启动. 启动后在未匹配到指定数据源时候回抛出异常,不启动会使用默认数据源. datasource: # 主库数据源 master: url: username: password: driver-class-name: com.mysql.cj.jdbc.Driver # 从库数据源 # slave: # # 从数据源开关/默认关闭 # enabled: false # url: # username: # password: druid: # 初始连接数 initialSize: 5 # 最小连接池数量 minIdle: 10 # 最大连接池数量 maxActive: 20 # 配置获取连接等待超时的时间 maxWait: 60000 # 配置连接超时时间 connectTimeout: 30000 # 配置网络超时时间 socketTimeout: 60000 # 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒 timeBetweenEvictionRunsMillis: 60000 # 配置一个连接在池中最小生存的时间,单位是毫秒 minEvictableIdleTimeMillis: 300000 # 配置一个连接在池中最大生存的时间,单位是毫秒 maxEvictableIdleTimeMillis: 900000 # 配置检测连接是否有效 validationQuery: SELECT 1 FROM DUAL testWhileIdle: true testOnBorrow: false testOnReturn: false webStatFilter: enabled: true statViewServlet: enabled: true # 设置白名单,不填则允许所有访问 allow: url-pattern: /druid/* # 控制台管理用户名和密码 login-username: ruoyi login-password: 123456 filter: stat: enabled: true # 慢SQL记录 log-slow-sql: true slow-sql-millis: 1000 merge-sql: true wall: config: multi-statement-allow: true
建表语句如下
SET NAMES utf8mb4; SET FOREIGN_KEY_CHECKS = 0; -- ---------------------------- -- Table structure for sys_database -- ---------------------------- DROP TABLE IF EXISTS `sys_database`; CREATE TABLE `sys_database` ( `database_id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键', `pool_name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '连接池名称', `driver_class_name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '驱动名', `url` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '数据库地址', `username` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '数据库用户名', `password` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '数据库密码', PRIMARY KEY (`database_id`) USING BTREE ) ENGINE = InnoDB AUTO_INCREMENT = 3 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = DYNAMIC; SET FOREIGN_KEY_CHECKS = 1;
数据源实体类如下
package com.ruoyi.common.core.domain.entity; import org.apache.commons.lang3.builder.ToStringBuilder; import org.apache.commons.lang3.builder.ToStringStyle; import com.ruoyi.common.annotation.Excel; import com.ruoyi.common.core.domain.BaseEntity; /** * 数据库管理对象 sys_database * * @author ruoyi * @date 2023-03-01 */ public class SysDatabase extends BaseEntity { private static final long serialVersionUID = 1L; /** 主键 */ private Long databaseId; /** 连接池名称 */ @Excel(name = "连接池名称") private String poolName; /** 驱动名 */ @Excel(name = "驱动名") private String driverClassName; /** 数据库地址 */ @Excel(name = "数据库地址") private String url; /** 数据库用户名 */ @Excel(name = "数据库用户名") private String username; /** 数据库密码 */ @Excel(name = "数据库密码") private String password; public void setDatabaseId(Long databaseId) { this.databaseId = databaseId; } public Long getDatabaseId() { return databaseId; } public void setPoolName(String poolName) { this.poolName = poolName; } public String getPoolName() { return poolName; } public void setDriverClassName(String driverClassName) { this.driverClassName = driverClassName; } public String getDriverClassName() { return driverClassName; } public void setUrl(String url) { this.url = url; } public String getUrl() { return url; } public void setUsername(String username) { this.username = username; } public String getUsername() { return username; } public void setPassword(String password) { this.password = password; } public String getPassword() { return password; } @Override public String toString() { return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE) .append("databaseId", getDatabaseId()) .append("poolName", getPoolName()) .append("driverClassName", getDriverClassName()) .append("url", getUrl()) .append("username", getUsername()) .append("password", getPassword()) .toString(); } }
import javax.sql.DataSource; import com.baomidou.dynamic.datasource.DynamicRoutingDataSource; @Autowired private DataSource dataSource; //这是官方示例,直接返回PoolName(就是yaml配置中的数据源名称)的Set @GetMapping @ApiOperation("获取当前所有数据源") public Set<String> now() { DynamicRoutingDataSource ds = (DynamicRoutingDataSource) dataSource; return ds.getDataSources().keySet(); } //如果只是想知道具体的数据源,输出查看PoolName即可,如下 public void getDataSources() { DynamicRoutingDataSource ds = (DynamicRoutingDataSource) dataSource; for (String poolName : ds.getDataSources().keySet()) { System.out.println("poolName:" + poolName); } }
import com.ruoyi.system.service.ISysDatabaseService; import javax.sql.DataSource; import com.baomidou.dynamic.datasource.DynamicRoutingDataSource; import org.springframework.beans.BeanUtils; @Autowired private ISysDatabaseService sysDatabaseService; @Autowired private DataSource dataSource; //通用数据源会根据maven中配置的连接池根据顺序依次选择。 //默认的顺序为druid>hikaricp>beecp>dbcp>spring basic @PostMapping("/add") @ApiOperation("通用添加数据源(推荐)") public Set<String> add(@Validated @RequestBody DataSourceDTO dto) { DataSourceProperty dataSourceProperty = new DataSourceProperty(); // 这里主要是将dto的属性赋值给dataSourceProperty //所以dataSourceProperty中必要的参数,dto都要提供 BeanUtils.copyProperties(dto, dataSourceProperty); DynamicRoutingDataSource ds = (DynamicRoutingDataSource) dataSource; DataSource dataSource = dataSourceCreator.createDataSource(dataSourceProperty); // PoolName就是我们yaml配置中说的数据源名称 ds.addDataSource(dto.getPoolName(), dataSource); return ds.getDataSources().keySet(); }
DynamicRoutingDataSource中记录数据源是以map形式,dataSourceMap的k就是poolName,所以如果想要更改poolName对应的数据源,直接覆盖同k的value即可。或者更为保险的做法可以先删除poolName对应的数据源,后续再次添加同名poolName数据源
import com.ruoyi.system.service.ISysDatabaseService;
import javax.sql.DataSource;
import com.baomidou.dynamic.datasource.DynamicRoutingDataSource;
@Autowired
private DataSource dataSource;
@DeleteMapping
@ApiOperation("删除数据源")
public String remove(String poolName) {
DynamicRoutingDataSource ds = (DynamicRoutingDataSource) dataSource;
ds.removeDataSource(poolName);
return "删除成功";
}
import com.baomidou.dynamic.datasource.DynamicRoutingDataSource;
public static void switchDataSource(String poolName) {
//需要注意的是手动切换的数据源,最好自己在合适的位置
//调用DynamicDataSourceContextHolder.clear()清空当前线程的数据源信息。
DynamicDataSourceContextHolder.clear();
//切换到对应poolName的数据源
DynamicDataSourceContextHolder.push(poolName);
}
package com.ruoyi.framework.interceptor; import com.baomidou.dynamic.datasource.DynamicRoutingDataSource; import com.baomidou.dynamic.datasource.creator.DefaultDataSourceCreator; import com.baomidou.dynamic.datasource.spring.boot.autoconfigure.DataSourceProperty; import com.baomidou.dynamic.datasource.toolkit.DynamicDataSourceContextHolder; import com.ruoyi.common.core.domain.entity.SysDatabase; import com.ruoyi.common.core.domain.entity.SysUser; import com.ruoyi.common.utils.ShiroUtils; import org.springframework.beans.BeanUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.servlet.HandlerInterceptor; import org.springframework.web.servlet.ModelAndView; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.sql.DataSource; import java.util.Objects; public class DynamicDatasourceInterceptor implements HandlerInterceptor { @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) { SysUser sysUser = ShiroUtils.getSysUser(); //获取当前登录用户信息 if(Objects.nonNull(sysUser) && Objects.nonNull(sysUser.getDatabase())){ SysDatabase database = sysUser.getDatabase(); //获取用户对应的数据源信息 DynamicDataSourceContextHolder.push(database.getPoolName()); //切换数据源 return true; } return true; } @Override public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) { } // @Override // public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) { // DynamicDataSourceContextHolder.clear(); // } }
package com.ruoyi.framework.config; import com.ruoyi.framework.interceptor.DynamicDatasourceInterceptor; import org.springframework.context.annotation.Configuration; import org.springframework.web.servlet.config.annotation.InterceptorRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; @Configuration public class DynamicDatasourceInterceptorConfig implements WebMvcConfigurer { @Override public void addInterceptors(InterceptorRegistry registry) { String[] path = {"/system/**"}; // 如果拦截全部可以设置为 /** String[] excludePath = {}; // 不需要拦截的接口路径 DynamicDatasourceInterceptor dynamicDatasourceInterceptor = new DynamicDatasourceInterceptor(); registry.addInterceptor(dynamicDatasourceInterceptor).addPathPatterns(path).excludePathPatterns(excludePath); } }
package com.ruoyi.framework.shiro.service; import com.baomidou.dynamic.datasource.DynamicRoutingDataSource; import com.baomidou.dynamic.datasource.creator.DefaultDataSourceCreator; import com.baomidou.dynamic.datasource.spring.boot.autoconfigure.DataSourceProperty; import com.ruoyi.common.config.datasource.DynamicDataSourceContextHolder; import com.ruoyi.common.core.domain.entity.SysDatabase; import com.ruoyi.system.service.ISysDatabaseService; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.BeanUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import javax.annotation.PostConstruct; import javax.sql.DataSource; import java.util.List; @Service public class InjectionAllDatasourceService { public static final Logger log = LoggerFactory.getLogger(DynamicDataSourceContextHolder.class); @Autowired private DataSource dataSource; @Autowired private DefaultDataSourceCreator dataSourceCreator; @Autowired private ISysDatabaseService databaseService; @PostConstruct public void init(){ log.info("项目启动中,加载用户数据"); List<SysDatabase> sysDatabases = databaseService.selectSysDatabaseList(new SysDatabase()); for (SysDatabase database:sysDatabases){ try { DataSourceProperty dataSourceProperty = new DataSourceProperty(); // 这里主要是将dto的属性赋值给dataSourceProperty //所以dataSourceProperty中必要的参数,dto都要提供 BeanUtils.copyProperties(database, dataSourceProperty); DynamicRoutingDataSource ds = (DynamicRoutingDataSource) dataSource; DataSource dataSource = dataSourceCreator.createDataSource(dataSourceProperty); // PoolName就是我们yaml配置中说的数据源名称 ds.addDataSource(database.getPoolName(), dataSource); } catch (Exception e){ e.printStackTrace(); } } log.info("项目启动中,加载用户数据完成"); } }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。