diff --git a/yudao-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/config/YudaoTenantAutoConfiguration.java b/yudao-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/config/YudaoTenantAutoConfiguration.java index fe32004767..641d4c51dd 100644 --- a/yudao-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/config/YudaoTenantAutoConfiguration.java +++ b/yudao-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/config/YudaoTenantAutoConfiguration.java @@ -18,6 +18,9 @@ import cn.iocoder.yudao.framework.tenant.core.web.TenantContextWebFilter; import cn.iocoder.yudao.framework.web.config.WebProperties; import cn.iocoder.yudao.framework.web.core.handler.GlobalExceptionHandler; import cn.iocoder.yudao.module.system.api.tenant.TenantApi; +import com.baomidou.dynamic.datasource.DynamicRoutingDataSource; +import com.baomidou.dynamic.datasource.creator.DataSourceCreator; +import com.baomidou.dynamic.datasource.creator.DefaultDataSourceCreator; import com.baomidou.dynamic.datasource.processor.DsProcessor; import com.baomidou.dynamic.datasource.processor.DsSpelExpressionProcessor; import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor; @@ -36,6 +39,7 @@ import org.springframework.data.redis.cache.RedisCacheWriter; import org.springframework.data.redis.connection.RedisConnectionFactory; import org.springframework.data.redis.core.RedisTemplate; +import javax.sql.DataSource; import java.util.Objects; @AutoConfiguration @@ -68,7 +72,12 @@ public class YudaoTenantAutoConfiguration { } @Bean - public DsProcessor dsProcessor() { + public DsProcessor dsProcessor( +// TenantFrameworkService tenantFrameworkService, +// DataSource dataSource, +// DefaultDataSourceCreator dataSourceCreator + ) { +// TenantDsProcessor tenantDsProcessor = new TenantDsProcessor(tenantFrameworkService, dataSourceCreator); TenantDsProcessor tenantDsProcessor = new TenantDsProcessor(); tenantDsProcessor.setNextProcessor(new DsSpelExpressionProcessor()); return tenantDsProcessor; diff --git a/yudao-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/core/db/dynamic/TenantDsProcessor.java b/yudao-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/core/db/dynamic/TenantDsProcessor.java index 6a86cef91c..565b418e17 100644 --- a/yudao-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/core/db/dynamic/TenantDsProcessor.java +++ b/yudao-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/core/db/dynamic/TenantDsProcessor.java @@ -1,18 +1,52 @@ package cn.iocoder.yudao.framework.tenant.core.db.dynamic; import cn.iocoder.yudao.framework.tenant.core.context.TenantContextHolder; +import cn.iocoder.yudao.framework.tenant.core.service.TenantFrameworkService; +import com.baomidou.dynamic.datasource.DynamicRoutingDataSource; +import com.baomidou.dynamic.datasource.creator.DefaultDataSourceCreator; import com.baomidou.dynamic.datasource.processor.DsProcessor; +import com.baomidou.dynamic.datasource.spring.boot.autoconfigure.DataSourceProperty; +import jodd.util.CollectionUtil; +import lombok.RequiredArgsConstructor; import org.aopalliance.intercept.MethodInvocation; +import org.springframework.context.annotation.Lazy; +import javax.annotation.Resource; +import javax.sql.DataSource; import java.util.Objects; /** * 基于 {@link TenantDS} 的数据源处理器 * + * 1. 如果有 @TenantDS 注解,返回该租户的数据源 + * 2. 如果该租户的数据源未创建,则进行创建 + * * @author 芋道源码 */ +@RequiredArgsConstructor public class TenantDsProcessor extends DsProcessor { + /** + * 用于获取租户数据源配置的 Service + */ + @Resource + @Lazy + private TenantFrameworkService tenantFrameworkService; + + /** + * 动态数据源 + */ + @Resource + @Lazy // 为什么添加 @Lazy 注解?因为它和 DynamicRoutingDataSource 相互依赖,导致无法初始化 + private DynamicRoutingDataSource dynamicRoutingDataSource; + + /** + * 用于创建租户数据源的 Creator + */ + @Resource + @Lazy + private DefaultDataSourceCreator dataSourceCreator; + @Override public boolean matches(String key) { return Objects.equals(key, TenantDS.KEY); @@ -20,12 +54,33 @@ public class TenantDsProcessor extends DsProcessor { @Override public String doDetermineDatasource(MethodInvocation invocation, String key) { + // 获得数据源配置 Long tenantId = TenantContextHolder.getRequiredTenantId(); - // TODO 芋艿:临时测试 - if (tenantId != 1) { - tenantId = 2L; + DataSourceProperty dataSourceProperty = tenantFrameworkService.getDataSourceProperty(tenantId); + // 创建 or 创建数据源,并返回数据源名字 + return createDatasourceIfAbsent(dataSourceProperty); + } + + private String createDatasourceIfAbsent(DataSourceProperty dataSourceProperty) { + // 1. 重点:如果数据源不存在,则进行创建 + if (isDataSourceNotExist(dataSourceProperty)) { + // 问题一:为什么要加锁?因为,如果多个线程同时执行到这里,会导致多次创建数据源 + // 问题二:为什么要使用 poolName 加锁?保证多个不同的 poolName 可以并发创建数据源 + // 问题三:为什么要使用 intern 方法?因为,intern 方法,会返回一个字符串的常量池中的引用 + // intern 的说明,可见 https://www.cnblogs.com/xrq730/p/6662232.html 文章 + synchronized (dataSourceProperty.getPoolName().intern()) { + if (isDataSourceNotExist(dataSourceProperty)) { + DataSource dataSource = dataSourceCreator.createDataSource(dataSourceProperty); + dynamicRoutingDataSource.addDataSource(dataSourceProperty.getPoolName(), dataSource); + } + } } - return "tenant_" + tenantId + "_ds"; + // 2. 返回数据源的名字 + return dataSourceProperty.getPoolName(); + } + + private boolean isDataSourceNotExist(DataSourceProperty dataSourceProperty) { + return !dynamicRoutingDataSource.getDataSources().containsKey(dataSourceProperty.getPoolName()); } } diff --git a/yudao-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/core/service/TenantFrameworkService.java b/yudao-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/core/service/TenantFrameworkService.java index 2ca474d0f5..3aa06a3761 100644 --- a/yudao-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/core/service/TenantFrameworkService.java +++ b/yudao-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/core/service/TenantFrameworkService.java @@ -1,5 +1,7 @@ package cn.iocoder.yudao.framework.tenant.core.service; +import com.baomidou.dynamic.datasource.spring.boot.autoconfigure.DataSourceProperty; + import java.util.List; /** @@ -23,4 +25,12 @@ public interface TenantFrameworkService { */ void validTenant(Long id); + /** + * 获得租户对应的数据源配置 + * + * @param id 租户编号 + * @return 数据源配置 + */ + DataSourceProperty getDataSourceProperty(Long id); + } diff --git a/yudao-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/core/service/TenantFrameworkServiceImpl.java b/yudao-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/core/service/TenantFrameworkServiceImpl.java index f2b7b27a86..26cd95e41a 100644 --- a/yudao-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/core/service/TenantFrameworkServiceImpl.java +++ b/yudao-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/core/service/TenantFrameworkServiceImpl.java @@ -2,7 +2,10 @@ package cn.iocoder.yudao.framework.tenant.core.service; import cn.iocoder.yudao.framework.common.exception.ServiceException; import cn.iocoder.yudao.framework.common.util.cache.CacheUtils; +import cn.iocoder.yudao.module.infra.api.db.dto.DataSourceConfigRespDTO; import cn.iocoder.yudao.module.system.api.tenant.TenantApi; +import cn.iocoder.yudao.module.system.api.tenant.dto.TenantDataSourceConfigRespDTO; +import com.baomidou.dynamic.datasource.spring.boot.autoconfigure.DataSourceProperty; import com.google.common.cache.CacheLoader; import com.google.common.cache.LoadingCache; import lombok.RequiredArgsConstructor; @@ -56,6 +59,28 @@ public class TenantFrameworkServiceImpl implements TenantFrameworkService { }); + /** + * 针对 {@link #getDataSourceProperty(Long)} 的缓存 + */ + private final LoadingCache dataSourcePropertyCache = CacheUtils.buildAsyncReloadingCache( + Duration.ofMinutes(1L), // 过期时间 1 分钟 + new CacheLoader() { + + @Override + public DataSourceProperty load(Long id) { + // 获得租户对应的数据源配置 + TenantDataSourceConfigRespDTO dataSourceConfig = tenantApi.getTenantDataSourceConfig(id); + if (dataSourceConfig == null) { + return null; + } + // 转换成 dynamic-datasource 配置 + return new DataSourceProperty() + .setPoolName(dataSourceConfig.getName()).setUrl(dataSourceConfig.getUrl()) + .setUsername(dataSourceConfig.getUsername()).setPassword(dataSourceConfig.getPassword()); + } + + }); + @Override @SneakyThrows public List getTenantIds() { @@ -70,4 +95,10 @@ public class TenantFrameworkServiceImpl implements TenantFrameworkService { } } + @Override + @SneakyThrows + public DataSourceProperty getDataSourceProperty(Long id) { + return dataSourcePropertyCache.get(id); + } + } diff --git a/yudao-module-infra/yudao-module-infra-api/src/main/java/cn/iocoder/yudao/module/infra/api/db/DataSourceConfigServiceApi.java b/yudao-module-infra/yudao-module-infra-api/src/main/java/cn/iocoder/yudao/module/infra/api/db/DataSourceConfigServiceApi.java new file mode 100644 index 0000000000..37db36f412 --- /dev/null +++ b/yudao-module-infra/yudao-module-infra-api/src/main/java/cn/iocoder/yudao/module/infra/api/db/DataSourceConfigServiceApi.java @@ -0,0 +1,20 @@ +package cn.iocoder.yudao.module.infra.api.db; + +import cn.iocoder.yudao.module.infra.api.db.dto.DataSourceConfigRespDTO; + +/** + * 数据源配置 API 接口 + * + * @author 芋道源码 + */ +public interface DataSourceConfigServiceApi { + + /** + * 获得数据源配置 + * + * @param id 编号 + * @return 数据源配置 + */ + DataSourceConfigRespDTO getDataSourceConfig(Long id); + +} diff --git a/yudao-module-infra/yudao-module-infra-api/src/main/java/cn/iocoder/yudao/module/infra/api/db/dto/DataSourceConfigRespDTO.java b/yudao-module-infra/yudao-module-infra-api/src/main/java/cn/iocoder/yudao/module/infra/api/db/dto/DataSourceConfigRespDTO.java new file mode 100644 index 0000000000..ace38802a5 --- /dev/null +++ b/yudao-module-infra/yudao-module-infra-api/src/main/java/cn/iocoder/yudao/module/infra/api/db/dto/DataSourceConfigRespDTO.java @@ -0,0 +1,35 @@ +package cn.iocoder.yudao.module.infra.api.db.dto; + +import lombok.Data; + +/** + * 数据源配置 Response DTO + * + * @author 芋道源码 + */ +@Data +public class DataSourceConfigRespDTO { + + /** + * 主键编号 + */ + private Long id; + /** + * 连接名 + */ + private String name; + + /** + * 数据源连接 + */ + private String url; + /** + * 用户名 + */ + private String username; + /** + * 密码 + */ + private String password; + +} diff --git a/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/api/db/DataSourceConfigServiceApiImpl.java b/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/api/db/DataSourceConfigServiceApiImpl.java new file mode 100644 index 0000000000..7da9699c4e --- /dev/null +++ b/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/api/db/DataSourceConfigServiceApiImpl.java @@ -0,0 +1,26 @@ +package cn.iocoder.yudao.module.infra.api.db; + +import cn.iocoder.yudao.module.infra.api.db.dto.DataSourceConfigRespDTO; +import cn.iocoder.yudao.module.infra.convert.db.DataSourceConfigConvert; +import cn.iocoder.yudao.module.infra.service.db.DataSourceConfigService; +import org.springframework.stereotype.Service; + +import javax.annotation.Resource; + +/** + * 数据源配置 API 实现类 + * + * @author 芋道源码 + */ +@Service +public class DataSourceConfigServiceApiImpl implements DataSourceConfigServiceApi { + + @Resource + private DataSourceConfigService dataSourceConfigService; + + @Override + public DataSourceConfigRespDTO getDataSourceConfig(Long id) { + return DataSourceConfigConvert.INSTANCE.convert02(dataSourceConfigService.getDataSourceConfig(id)); + } + +} diff --git a/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/convert/db/DataSourceConfigConvert.java b/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/convert/db/DataSourceConfigConvert.java index d81d85cee6..96f6caba2e 100755 --- a/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/convert/db/DataSourceConfigConvert.java +++ b/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/convert/db/DataSourceConfigConvert.java @@ -4,6 +4,7 @@ import java.util.*; import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.infra.api.db.dto.DataSourceConfigRespDTO; import org.mapstruct.Mapper; import org.mapstruct.factory.Mappers; import cn.iocoder.yudao.module.infra.controller.admin.db.vo.*; @@ -27,4 +28,6 @@ public interface DataSourceConfigConvert { List convertList(List list); + DataSourceConfigRespDTO convert02(DataSourceConfigDO bean); + } diff --git a/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/tenant/TenantApi.java b/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/tenant/TenantApi.java index 1fad83ed6d..c4fd1f6b92 100644 --- a/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/tenant/TenantApi.java +++ b/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/tenant/TenantApi.java @@ -1,5 +1,7 @@ package cn.iocoder.yudao.module.system.api.tenant; +import cn.iocoder.yudao.module.system.api.tenant.dto.TenantDataSourceConfigRespDTO; + import java.util.List; /** @@ -23,4 +25,12 @@ public interface TenantApi { */ void validateTenant(Long id); + /** + * 获得租户的数据源配置 + * + * @param tenantId 租户编号 + * @return 数据源配置 + */ + TenantDataSourceConfigRespDTO getTenantDataSourceConfig(Long tenantId); + } diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/api/tenant/TenantApiImpl.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/api/tenant/TenantApiImpl.java index 25ea260c57..297198b9ea 100644 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/api/tenant/TenantApiImpl.java +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/api/tenant/TenantApiImpl.java @@ -1,5 +1,9 @@ package cn.iocoder.yudao.module.system.api.tenant; +import cn.iocoder.yudao.module.infra.api.db.DataSourceConfigServiceApi; +import cn.iocoder.yudao.module.system.api.tenant.dto.TenantDataSourceConfigRespDTO; +import cn.iocoder.yudao.module.system.convert.tenant.TenantConvert; +import cn.iocoder.yudao.module.system.dal.dataobject.tenant.TenantDO; import cn.iocoder.yudao.module.system.service.tenant.TenantService; import org.springframework.stereotype.Service; @@ -17,6 +21,9 @@ public class TenantApiImpl implements TenantApi { @Resource private TenantService tenantService; + @Resource + private DataSourceConfigServiceApi dataSourceConfigServiceApi; + @Override public List getTenantIdList() { return tenantService.getTenantIdList(); @@ -27,4 +34,16 @@ public class TenantApiImpl implements TenantApi { tenantService.validTenant(id); } + @Override + public TenantDataSourceConfigRespDTO getTenantDataSourceConfig(Long tenantId) { + // 获得租户信息 + TenantDO tenant = tenantService.getTenant(tenantId); + if (tenant == null) { + return null; + } + // 获得租户的数据源配置 + return TenantConvert.INSTANCE.convert( + dataSourceConfigServiceApi.getDataSourceConfig(tenant.getDatasourceConfigId())); + } + } diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/convert/tenant/TenantConvert.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/convert/tenant/TenantConvert.java index d40e481d80..f9c9bfc51e 100755 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/convert/tenant/TenantConvert.java +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/convert/tenant/TenantConvert.java @@ -1,6 +1,8 @@ package cn.iocoder.yudao.module.system.convert.tenant; import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.infra.api.db.dto.DataSourceConfigRespDTO; +import cn.iocoder.yudao.module.system.api.tenant.dto.TenantDataSourceConfigRespDTO; import cn.iocoder.yudao.module.system.controller.admin.tenant.vo.tenant.TenantCreateReqVO; import cn.iocoder.yudao.module.system.controller.admin.tenant.vo.tenant.TenantExcelVO; import cn.iocoder.yudao.module.system.controller.admin.tenant.vo.tenant.TenantRespVO; @@ -42,4 +44,6 @@ public interface TenantConvert { return reqVO; } + TenantDataSourceConfigRespDTO convert(DataSourceConfigRespDTO bean); + } diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/tenant/TenantDO.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/tenant/TenantDO.java index 17b42efa3a..710d9e7c7a 100644 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/tenant/TenantDO.java +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/tenant/TenantDO.java @@ -79,4 +79,13 @@ public class TenantDO extends BaseDO { */ private Integer accountCount; + /** + * 数据源配置编号 + * + * 多租户采用“分库”方案时,通过该字段配置所在数据源 + * + * 关联 DataSourceConfigDO 的 id 字段 + */ + private Long datasourceConfigId; + } diff --git a/yudao-server/src/main/resources/application-dev.yaml b/yudao-server/src/main/resources/application-dev.yaml index 4a20cdfb3a..340b1eb261 100644 --- a/yudao-server/src/main/resources/application-dev.yaml +++ b/yudao-server/src/main/resources/application-dev.yaml @@ -44,15 +44,11 @@ spring: primary: master datasource: master: - name: ruoyi-vue-pro - url: jdbc:mysql://400-infra.server.iocoder.cn:3306/${spring.datasource.dynamic.datasource.master.name}?useSSL=false&serverTimezone=UTC&useSSL=false&allowPublicKeyRetrieval=true - driver-class-name: com.mysql.jdbc.Driver + url: jdbc:mysql://400-infra.server.iocoder.cn:3306/ruoyi-vue-pro?useSSL=false&serverTimezone=UTC&useSSL=false&allowPublicKeyRetrieval=true username: root password: 3WLiVUBEwTbvAfsh slave: # 模拟从库,可根据自己需要修改 # 模拟从库,可根据自己需要修改 - name: ruoyi-vue-pro - url: jdbc:mysql://400-infra.server.iocoder.cn:3306/${spring.datasource.dynamic.datasource.slave.name}?useSSL=false&serverTimezone=UTC&useSSL=false&allowPublicKeyRetrieval=true - driver-class-name: com.mysql.jdbc.Driver + url: jdbc:mysql://400-infra.server.iocoder.cn:3306/ruoyi-vue-pro?useSSL=false&serverTimezone=UTC&useSSL=false&allowPublicKeyRetrieval=true username: root password: 3WLiVUBEwTbvAfsh diff --git a/yudao-server/src/main/resources/application-local.yaml b/yudao-server/src/main/resources/application-local.yaml index a4aad05520..e88898544a 100644 --- a/yudao-server/src/main/resources/application-local.yaml +++ b/yudao-server/src/main/resources/application-local.yaml @@ -44,37 +44,25 @@ spring: primary: master datasource: master: - name: ruoyi-vue-pro-master - url: jdbc:mysql://127.0.0.1:3306/${spring.datasource.dynamic.datasource.master.name}?useSSL=false&serverTimezone=UTC&useSSL=false&allowPublicKeyRetrieval=true # MySQL Connector/J 8.X 连接的示例 - # url: jdbc:mysql://127.0.0.1:3306/${spring.datasource.dynamic.datasource.master.name}?useSSL=false&allowPublicKeyRetrieval=true&useUnicode=true&characterEncoding=UTF-8&serverTimezone=CTT # MySQL Connector/J 5.X 连接的示例 - # url: jdbc:postgresql://127.0.0.1:5432/${spring.datasource.dynamic.datasource.slave.name} # PostgreSQL 连接的示例 + url: jdbc:mysql://127.0.0.1:3306/ruoyi-vue-pro-master?useSSL=false&serverTimezone=UTC&useSSL=false&allowPublicKeyRetrieval=true # MySQL Connector/J 8.X 连接的示例 + # url: jdbc:mysql://127.0.0.1:3306/ruoyi-vue-pro-master?useSSL=false&allowPublicKeyRetrieval=true&useUnicode=true&characterEncoding=UTF-8&serverTimezone=CTT # MySQL Connector/J 5.X 连接的示例 + # url: jdbc:postgresql://127.0.0.1:5432/ruoyi-vue-pro # PostgreSQL 连接的示例 # url: jdbc:oracle:thin:@127.0.0.1:1521:xe # Oracle 连接的示例 - # url: jdbc:sqlserver://127.0.0.1:1433;DatabaseName=${spring.datasource.dynamic.datasource.master.name} # SQLServer 连接的示例 + # url: jdbc:sqlserver://127.0.0.1:1433;DatabaseName=ruoyi-vue-pro-master # SQLServer 连接的示例 username: root password: 123456 # username: sa # password: JSm:g(*%lU4ZAkz06cd52KqT3)i1?H7W slave: # 模拟从库,可根据自己需要修改 - name: ruoyi-vue-pro - url: jdbc:mysql://127.0.0.1:3306/${spring.datasource.dynamic.datasource.slave.name}?useSSL=false&serverTimezone=UTC&useSSL=false&allowPublicKeyRetrieval=true # MySQL Connector/J 8.X 连接的示例 - # url: jdbc:mysql://127.0.0.1:3306/${spring.datasource.dynamic.datasource.slave.name}?useSSL=false&allowPublicKeyRetrieval=true&useUnicode=true&characterEncoding=UTF-8&serverTimezone=CTT # MySQL Connector/J 5.X 连接的示例 - # url: jdbc:postgresql://127.0.0.1:5432/${spring.datasource.dynamic.datasource.slave.name} # PostgreSQL 连接的示例 + url: jdbc:mysql://127.0.0.1:3306/ruoyi-vue-pro?useSSL=false&serverTimezone=UTC&useSSL=false&allowPublicKeyRetrieval=true # MySQL Connector/J 8.X 连接的示例 + # url: jdbc:mysql://127.0.0.1:3306/ruoyi-vue-pro?useSSL=false&allowPublicKeyRetrieval=true&useUnicode=true&characterEncoding=UTF-8&serverTimezone=CTT # MySQL Connector/J 5.X 连接的示例 + # url: jdbc:postgresql://127.0.0.1:5432/ruoyi-vue-pro # PostgreSQL 连接的示例 # url: jdbc:oracle:thin:@127.0.0.1:1521:xe # Oracle 连接的示例 - # url: jdbc:sqlserver://127.0.0.1:1433;DatabaseName=${spring.datasource.dynamic.datasource.slave.name} # SQLServer 连接的示例 + # url: jdbc:sqlserver://127.0.0.1:1433;DatabaseName=ruoyi-vue-pro # SQLServer 连接的示例 username: root password: 123456 # username: sa # password: JSm:g(*%lU4ZAkz06cd52KqT3)i1?H7W - tenant_1_ds: - name: tenant_1 - url: jdbc:mysql://127.0.0.1:3306/ruoyi-vue-pro-tenant-a?useSSL=false&serverTimezone=UTC&useSSL=false&allowPublicKeyRetrieval=true - username: root - password: 123456 - tenant_2_ds: - name: tenant_2 - url: jdbc:mysql://127.0.0.1:3306/ruoyi-vue-pro-tenant-b?useSSL=false&serverTimezone=UTC&useSSL=false&allowPublicKeyRetrieval=true - username: root - password: 123456 # Redis 配置。Redisson 默认的配置足够使用,一般不需要进行调优 redis: