This commit is contained in:
2023-06-28 17:48:50 +08:00
parent 4a3c958e1a
commit a567befac3
21 changed files with 309 additions and 122 deletions

View File

@ -1,13 +1,13 @@
UPDATE sys_dept set tenant_id = '1';
UPDATE sys_menu set tenant_id = '1';
UPDATE sys_post set tenant_id = '1';
UPDATE sys_role set tenant_id = '1';
UPDATE sys_user set tenant_id = '1';
UPDATE sys_config set tenant_id = '1';
UPDATE sys_login_log set tenant_id = '1';
UPDATE sys_role_dept set tenant_id = '1';
UPDATE sys_role_menu set tenant_id = '1';
UPDATE sys_user_post set tenant_id = '1';
UPDATE sys_user_role set tenant_id = '1';
UPDATE sys_dict_data set tenant_id = '1';
UPDATE sys_dict_type set tenant_id = '1';
UPDATE sys_dept set tenant_id = '2';
UPDATE sys_menu set tenant_id = '2';
UPDATE sys_post set tenant_id = '2';
UPDATE sys_role set tenant_id = '2';
UPDATE sys_user set tenant_id = '2';
UPDATE sys_config set tenant_id = '2';
UPDATE sys_login_log set tenant_id = '2';
UPDATE sys_role_dept set tenant_id = '2';
UPDATE sys_role_menu set tenant_id = '2';
UPDATE sys_user_post set tenant_id = '2';
UPDATE sys_user_role set tenant_id = '2';
UPDATE sys_dict_data set tenant_id = '2';
UPDATE sys_dict_type set tenant_id = '2';

View File

@ -2,7 +2,7 @@ qiaoba:
file-upload-path: C:/${spring.application.name}/uploadPath/
dataSources:
- driver: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://192.168.0.202:3306/${spring.application.name}?useUnicode=true&characterEncoding=utf-8&serverTimezone=Asia/Shanghai&nullCatalogMeansCurrent=true&allowMultiQueries=true
url: jdbc:mysql://192.168.0.202:3306/${spring.application.name}?databaseTerm=SCHEMA&useUnicode=true&characterEncoding=utf-8&serverTimezone=Asia/Shanghai&nullCatalogMeansCurrent=true&allowMultiQueries=true
username: root
password: Root123456789.
#连接池初始化大小
@ -12,7 +12,7 @@ qiaoba:
#最大连接池数量
max-active: 20
- driver: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://192.168.0.203:3306/${spring.application.name}?useUnicode=true&characterEncoding=utf-8&serverTimezone=Asia/Shanghai&nullCatalogMeansCurrent=true&allowMultiQueries=true
url: jdbc:mysql://192.168.0.203:3306/${spring.application.name}?databaseTerm=SCHEMA&useUnicode=true&characterEncoding=utf-8&serverTimezone=Asia/Shanghai&nullCatalogMeansCurrent=true&allowMultiQueries=true
username: root
password: Root123456789.
#连接池初始化大小
@ -22,7 +22,16 @@ qiaoba:
#最大连接池数量
max-active: 20
# - driver: org.postgresql.Driver
# url: jdbc:postgresql://192.168.0.202:5432/mydb?currentSchema=qiaoba-boot&useUnicode=true&characterEncoding=utf-8&serverTimezone=Asia/Shanghai&nullCatalogMeansCurrent=true&allowMultiQueries=true
# username: postgres
# password: postgres
# #连接池初始化大小
# initial-size: 5
# #最小空闲线程数
# min-idle: 10
# #最大连接池数量
# max-active: 20
mybatis-plus:
configuration:
# 自动驼峰命名规则camel case映射

View File

@ -5,6 +5,7 @@ spring:
#新创建的bean覆盖旧的bean
allow-bean-definition-overriding: true
application:
# DbName / FileDirName / SchemaPrefix
name: qiaoba-boot
profiles:
active: dev

View File

@ -30,7 +30,12 @@ public enum DatasourceErrorCode {
/**
* 创建表错误
*/
CREATE_TABLE_ERROR(50104, "创建表错误");
CREATE_TABLE_ERROR(50104, "创建表错误"),
/**
* 创建模式/库错误
*/
CREATE_SCHEMA_ERROR(50105, "创建模式/库错误");
private final Integer code;
private final String msg;

View File

@ -22,7 +22,7 @@ public enum DataBaseEnum {
* MySQL
*/
MY_SQL("MySQL",
"jdbc:mysql://{}:{}/{}?useUnicode=true&characterEncoding=utf-8&serverTimezone=Asia/Shanghai&nullCatalogMeansCurrent=true&allowMultiQueries=true",
"jdbc:mysql://{}:{}/{}?databaseTerm=SCHEMA&useUnicode=true&characterEncoding=utf-8&serverTimezone=Asia/Shanghai&nullCatalogMeansCurrent=true&allowMultiQueries=true",
"com.mysql.cj.jdbc.Driver",
"SELECT 1"),

View File

@ -8,6 +8,10 @@ import com.alibaba.druid.pool.DruidPooledConnection;
import com.qiaoba.common.base.constants.TenantConstant;
import com.qiaoba.common.base.context.BaseContext;
import com.qiaoba.common.base.enums.BaseEnum;
import com.qiaoba.common.database.context.BackupDatasourceContext;
import com.qiaoba.common.database.context.DynamicDataSourceContext;
import com.qiaoba.common.database.context.PrimaryDatasourceContext;
import com.qiaoba.common.database.context.TenantDbTypeContext;
import com.qiaoba.common.database.entity.DynamicDataSource;
import com.qiaoba.common.database.monitor.NotOnlineDatasourceMonitor;
import com.qiaoba.common.database.properties.DataSourceProperties;
@ -24,7 +28,6 @@ import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
/**
* 多数据源配置
@ -52,25 +55,11 @@ public class DynamicDataSourceConfig {
*/
public static Boolean COMPLETE_LOAD_DATASOURCE = false;
/**
* 主要数据源
*/
public static Map<Object, Object> PRIMARY_DATASOURCE_MAP = new ConcurrentHashMap<>();
/**
* 备用数据源-每次取0索引
*/
public static Map<String, List<DynamicDataSource>> BACKUP_DATASOURCE_MAP = new ConcurrentHashMap<>();
/**
* 租户 ids
*/
public static List<String> TENANT_IDS = ListUtil.toList(TenantConstant.DEFAULT_TENANT_ID);
/**
* 租户数据源类型
*/
public static Map<String, String> TENANT_DATASOURCE_TYPE_MAP = new ConcurrentHashMap<>();
/**
* 把DynamicDataSourceContext 纳入容器管理其他地方使用DynamicDataSourceConfig 类可以直接从容器取对象并调用freshDataSource方法
@ -85,7 +74,7 @@ public class DynamicDataSourceConfig {
}
public static DruidDataSource getPrimaryDataSource(String tenantId) {
return (DruidDataSource) PRIMARY_DATASOURCE_MAP.get(tenantId);
return (DruidDataSource) PrimaryDatasourceContext.get(tenantId);
}
private void initDefault() {
@ -105,13 +94,13 @@ public class DynamicDataSourceConfig {
}
}
if (CollUtil.isEmpty(PRIMARY_DATASOURCE_MAP)) {
if (CollUtil.isEmpty(PrimaryDatasourceContext.getAll())) {
log.error("主系统配置数据源全部无效, 请检查 yml 中相关配置");
}
// 其他数据源备用
addBackupMap(TenantConstant.DEFAULT_TENANT_ID, dataSources);
// 刷新数据源
this.dataSource.freshDataSource(PRIMARY_DATASOURCE_MAP);
this.dataSource.freshDataSource(PrimaryDatasourceContext.getAll());
}
private void initTenant() {
@ -143,29 +132,25 @@ public class DynamicDataSourceConfig {
}
BaseContext.clearAllHolder();
// 刷新数据源
dataSource.freshDataSource(PRIMARY_DATASOURCE_MAP);
dataSource.freshDataSource(PrimaryDatasourceContext.getAll());
}
public void deleteTenantDataSource(String tenantId) {
PRIMARY_DATASOURCE_MAP.remove(tenantId);
dataSource.freshDataSource(PRIMARY_DATASOURCE_MAP);
}
public void changePrimaryDatasource(String tenantId, Object datasource) {
PRIMARY_DATASOURCE_MAP.put(tenantId, datasource);
PrimaryDatasourceContext.set(tenantId, datasource);
// 将数据源的类型保存
DruidPooledConnection connection = null;
try {
connection = ((DruidDataSource) datasource).getConnection();
TENANT_DATASOURCE_TYPE_MAP.put(tenantId, connection.getMetaData().getDatabaseProductName());
TenantDbTypeContext.set(tenantId, connection.getMetaData().getDatabaseProductName());
} catch (SQLException e) {
e.printStackTrace();
} finally {
// 归还 connection
IoUtil.close(connection);
}
dataSource.freshDataSource(PRIMARY_DATASOURCE_MAP);
dataSource.freshDataSource(PrimaryDatasourceContext.getAll());
}
public static Object buildDataSource(String tenantId, DynamicDataSource dynamicDataSource) {
@ -183,7 +168,7 @@ public class DynamicDataSourceConfig {
dataSource.setInitialSize(dynamicDataSource.getInitialSize());
dataSource.setMinIdle(dynamicDataSource.getMinIdle());
dataSource.setMaxActive(dynamicDataSource.getMaxActive());
//dataSource.setKeepAlive(false);
try {
// 初始化数据源
dataSource.init();
@ -199,7 +184,7 @@ public class DynamicDataSourceConfig {
*/
@PreDestroy
public void close() {
Set<Map.Entry<Object, Object>> entries = PRIMARY_DATASOURCE_MAP.entrySet();
Set<Map.Entry<Object, Object>> entries = PrimaryDatasourceContext.getAll().entrySet();
for (Map.Entry<Object, Object> entry : entries) {
DruidDataSource dataSource = (DruidDataSource) entry.getValue();
IoUtil.close(dataSource);
@ -209,10 +194,10 @@ public class DynamicDataSourceConfig {
private void addPrimaryMap(String tenantId, Object dataSource) {
if (Objects.nonNull(dataSource)) {
try {
PRIMARY_DATASOURCE_MAP.put(tenantId, dataSource);
PrimaryDatasourceContext.set(tenantId, dataSource);
// 将数据源的类型保存
DruidPooledConnection connection = ((DruidDataSource) dataSource).getConnection();
TENANT_DATASOURCE_TYPE_MAP.put(tenantId, connection.getMetaData().getDatabaseProductName());
TenantDbTypeContext.set(tenantId, connection.getMetaData().getDatabaseProductName());
// 归还 connection
IoUtil.close(connection);
} catch (SQLException e) {
@ -223,7 +208,7 @@ public class DynamicDataSourceConfig {
private void addBackupMap(String tenantId, List<DynamicDataSource> dataSources) {
if (CollUtil.isNotEmpty(dataSources)) {
BACKUP_DATASOURCE_MAP.put(tenantId, dataSources);
BackupDatasourceContext.set(tenantId, dataSources);
}
}
@ -235,6 +220,6 @@ public class DynamicDataSourceConfig {
public void setDefaultSetting() {
BaseContext.setDataSource(TenantConstant.DEFAULT_TENANT_ID);
BaseContext.setTenantId(TenantConstant.DEFAULT_TENANT_ID);
BaseContext.setDatabaseType(TENANT_DATASOURCE_TYPE_MAP.get(TenantConstant.DEFAULT_TENANT_ID));
BaseContext.setDatabaseType(TenantDbTypeContext.getDefault());
}
}

View File

@ -0,0 +1,44 @@
package com.qiaoba.common.database.context;
import com.qiaoba.common.database.entity.DynamicDataSource;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
/**
* 备用(未在使用)数据源
*
* @author ailanyin
* @version 1.0
* @since 2023/6/28 10:36
*/
public class BackupDatasourceContext {
/**
* 备用数据源
*/
private static Map<String, List<DynamicDataSource>> BACKUP_DATASOURCE_MAP = new ConcurrentHashMap<>();
/**
* 获取租户备用数据源
*
* @param tenantId 租户ID
* @return 数据源集合
*/
public static List<DynamicDataSource> get(String tenantId) {
return BACKUP_DATASOURCE_MAP.get(tenantId);
}
/**
* 设置租户备用数据源
*
* @param tenantId 租户ID
* @param list 数据源集合
*/
public static void set(String tenantId, List<DynamicDataSource> list) {
BACKUP_DATASOURCE_MAP.put(tenantId, list);
}
}

View File

@ -1,4 +1,4 @@
package com.qiaoba.common.database.config;
package com.qiaoba.common.database.context;
import com.qiaoba.common.base.constants.TenantConstant;
import com.qiaoba.common.base.context.BaseContext;

View File

@ -0,0 +1,63 @@
package com.qiaoba.common.database.context;
import com.qiaoba.common.base.constants.TenantConstant;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
/**
* 主要(正在使用)数据源
*
* @author ailanyin
* @version 1.0
* @since 2023/6/28 10:36
*/
public class PrimaryDatasourceContext {
/**
* 主要数据源
*/
private static Map<Object, Object> PRIMARY_DATASOURCE_MAP = new ConcurrentHashMap<>();
public static Map<Object, Object> getAll() {
return PRIMARY_DATASOURCE_MAP;
}
/**
* 获取租户主要数据源
*
* @param tenantId 租户ID
* @return 数据源
*/
public static Object get(String tenantId) {
return PRIMARY_DATASOURCE_MAP.get(tenantId);
}
/**
* 获取默认(主)主要数据源
*
* @return 数据源
*/
public static Object getDefault() {
return PRIMARY_DATASOURCE_MAP.get(TenantConstant.DEFAULT_TENANT_ID);
}
/**
* 设置租户主要数据源
*
* @param tenantId 租户ID
* @param datasource 数据源
*/
public static void set(String tenantId, Object datasource) {
PRIMARY_DATASOURCE_MAP.put(tenantId, datasource);
}
/**
* 删除
*
* @param tenantId 租户ID
*/
public static void remove(String tenantId) {
PRIMARY_DATASOURCE_MAP.remove(tenantId);
}
}

View File

@ -0,0 +1,59 @@
package com.qiaoba.common.database.context;
import com.qiaoba.common.base.constants.TenantConstant;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
/**
* 租户数据源类型
*
* @author ailanyin
* @version 1.0
* @since 2023/6/28 10:25
*/
public class TenantDbTypeContext {
/**
* 租户数据源类型
*/
private static Map<String, String> TENANT_DATASOURCE_TYPE_MAP = new ConcurrentHashMap<>();
/**
* 获取租户数据源类型
*
* @param tenantId 租户ID
* @return 数据源类型
*/
public static String get(String tenantId) {
return TENANT_DATASOURCE_TYPE_MAP.get(tenantId);
}
/**
* 设置租户数据源类型
*
* @param tenantId 租户ID
* @param dbType 数据源类型
*/
public static void set(String tenantId, String dbType) {
TENANT_DATASOURCE_TYPE_MAP.put(tenantId, dbType);
}
/**
* 获取默认(主)数据源类型
*
* @return 数据源类型
*/
public static String getDefault() {
return TENANT_DATASOURCE_TYPE_MAP.get(TenantConstant.DEFAULT_TENANT_ID);
}
/**
* 设置默认(主)数据源类型
*
* @param dbType 数据源类型
*/
public static void set(String dbType) {
set(TenantConstant.DEFAULT_TENANT_ID, dbType);
}
}

View File

@ -1,7 +1,7 @@
package com.qiaoba.common.database.factories;
import com.qiaoba.common.database.config.DynamicDataSourceConfig;
import com.qiaoba.common.database.config.DynamicDataSourceContext;
import com.qiaoba.common.database.context.DynamicDataSourceContext;
import com.qiaoba.common.database.properties.DataSourceProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

View File

@ -1,17 +1,19 @@
package com.qiaoba.common.database.interceptors;
import cn.hutool.core.io.IoUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.db.sql.SqlExecutor;
import com.baomidou.mybatisplus.extension.plugins.inner.InnerInterceptor;
import com.qiaoba.common.base.constants.BaseConstant;
import com.qiaoba.common.base.constants.TenantConstant;
import com.qiaoba.common.base.context.BaseContext;
import com.qiaoba.common.database.utils.JdbcUtil;
import com.qiaoba.common.database.utils.SqlUtil;
import com.qiaoba.common.database.context.TenantDbTypeContext;
import com.qiaoba.common.database.utils.DbUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.executor.statement.StatementHandler;
import org.postgresql.jdbc.PgConnection;
import org.springframework.beans.factory.annotation.Value;
import javax.annotation.Resource;
import java.sql.Connection;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Objects;
/**
@ -21,17 +23,22 @@ import java.util.Objects;
* @version 1.0
* @since 2023-04-25 22:48:43
*/
@Slf4j
public class SchemaInterceptor implements InnerInterceptor {
@Value("${spring.application.name}")
private String schemaPrefix;
@Override
public void beforePrepare(StatementHandler sh, Connection conn, Integer transactionTimeout) {
if (Objects.nonNull(BaseContext.isSchemaMode()) && BaseContext.isSchemaMode()) {
try {
conn.unwrap(PgConnection.class).setSchema("qiaoba-boot-2");
// schemaPrefix + '-' + tenantId
// eg: schema = qiaoba-boot-2
DbUtil.setSchema(TenantDbTypeContext.getDefault(), conn, schemaPrefix + BaseConstant.HYPHEN_JOIN_STR + BaseContext.getTenantId());
} catch (SQLException e) {
e.printStackTrace();
log.info("切换SCHEMA失败, 原因: {}", e.getMessage());
}
}
}

View File

@ -5,6 +5,7 @@ import cn.hutool.core.collection.ListUtil;
import com.baomidou.lock.LockInfo;
import com.baomidou.lock.LockTemplate;
import com.qiaoba.common.database.config.DynamicDataSourceConfig;
import com.qiaoba.common.database.context.BackupDatasourceContext;
import com.qiaoba.common.database.entity.DynamicDataSource;
import com.qiaoba.common.database.utils.JdbcUtil;
import lombok.extern.slf4j.Slf4j;
@ -98,9 +99,9 @@ public class NotOnlineDatasourceMonitor {
}
private void addBackupMap(String tenantId, DynamicDataSource dataSource) {
List<DynamicDataSource> dataSourceList = DynamicDataSourceConfig.BACKUP_DATASOURCE_MAP.get(tenantId);
List<DynamicDataSource> dataSourceList = BackupDatasourceContext.get(tenantId);
if (CollUtil.isEmpty(dataSourceList)) {
DynamicDataSourceConfig.BACKUP_DATASOURCE_MAP.put(tenantId, ListUtil.toList(dataSource));
BackupDatasourceContext.set(tenantId, ListUtil.toList(dataSource));
} else {
dataSourceList.add(dataSource);
}

View File

@ -8,6 +8,8 @@ import com.baomidou.lock.LockTemplate;
import com.qiaoba.common.base.constants.TenantConstant;
import com.qiaoba.common.base.enums.DataBaseEnum;
import com.qiaoba.common.database.config.DynamicDataSourceConfig;
import com.qiaoba.common.database.context.BackupDatasourceContext;
import com.qiaoba.common.database.context.PrimaryDatasourceContext;
import com.qiaoba.common.database.entity.DynamicDataSource;
import com.qiaoba.common.database.service.DynamicDatasourceService;
import com.qiaoba.common.database.utils.JdbcUtil;
@ -78,8 +80,7 @@ public class OnlineDatasourceMonitor {
private void tryConnect() {
for (String tenantId : DynamicDataSourceConfig.TENANT_IDS) {
Object primary = DynamicDataSourceConfig.PRIMARY_DATASOURCE_MAP.get(tenantId);
DynamicDataSourceConfig.BACKUP_DATASOURCE_MAP.get(tenantId);
Object primary = PrimaryDatasourceContext.get(tenantId);
if (Objects.isNull(primary)) {
// 说明初始化主要数据源的时候出错
log.error("租户[{}]-目前主数据源异常, 开始切换备用数据源", tenantId);
@ -110,7 +111,7 @@ public class OnlineDatasourceMonitor {
// 关闭原有异常数据源
IoUtil.close(dataSource);
// 在数据源Map中删除
DynamicDataSourceConfig.PRIMARY_DATASOURCE_MAP.remove(tenantId);
PrimaryDatasourceContext.remove(tenantId);
}
// 将原有异常数据源加入到错误数据源Map, 等待重试
addErrorDatasource(tenantId, dataSource);
@ -130,7 +131,7 @@ public class OnlineDatasourceMonitor {
*/
private Boolean backToPrimary(String tenantId) {
// 备用数据源
List<DynamicDataSource> dataSources = DynamicDataSourceConfig.BACKUP_DATASOURCE_MAP.get(tenantId);
List<DynamicDataSource> dataSources = BackupDatasourceContext.get(tenantId);
if (CollUtil.isEmpty(dataSources)) {
log.error("租户:[{}]切换备用数据源失败, 原因: 没有备用数据源", tenantId);
return false;

View File

@ -1,23 +1,36 @@
package com.qiaoba.module.tenant.utils;
package com.qiaoba.common.database.utils;
import com.qiaoba.common.base.enums.DataBaseEnum;
import org.apache.ibatis.jdbc.ScriptRunner;
import org.postgresql.jdbc.PgConnection;
import org.springframework.core.io.ClassPathResource;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.sql.Connection;
import java.sql.SQLException;
/**
* 数据库工具类
*
* @author ailanyin
* @version 1.0
* @since 2023/6/27 16:11
* @since 2023/6/28 8:52
*/
public class DbUtil {
public static void setSchema(String dbType, Connection conn, String schema) throws SQLException {
if (DataBaseEnum.MY_SQL.getType().equals(dbType)) {
conn.setSchema(schema);
} else if (DataBaseEnum.ORACLE.getType().equals(dbType)) {
} else if (DataBaseEnum.POSTGRE_SQL.getType().equals(dbType)) {
conn.unwrap(PgConnection.class).setSchema(schema);
} else if (DataBaseEnum.SQL_SERVER.getType().equals(dbType)) {
}
}
public static void runScript(Connection conn, String filePath) throws IOException {
ClassPathResource resource = new ClassPathResource(filePath);
File file = resource.getFile();

View File

@ -8,10 +8,7 @@ import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.Statement;
import java.sql.*;
/**
* JdbcUtil
@ -104,6 +101,18 @@ public class JdbcUtil {
}
public static void main(String[] args) {
System.out.println(check("oracle.jdbc.OracleDriver", "jdbc:oracle:thin:@//192.168.0.205:1521/ORCL", "system", "root"));
Connection connection = getConnection("oracle.jdbc.OracleDriver", "jdbc:oracle:thin:@//192.168.0.205:1521/ORCL", "system", "root");
try {
DbUtil.setSchema("Oracle",connection,"scott");
} catch (SQLException e) {
e.printStackTrace();
} finally {
try {
connection.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
System.out.println();
}
}

View File

@ -1,28 +0,0 @@
package com.qiaoba.common.database.utils;
import cn.hutool.core.io.IoUtil;
import java.sql.Connection;
import java.sql.SQLException;
import java.sql.Statement;
/**
* SqlUtil
*
* @author ailanyin
* @version 1.0
* @since 2023/6/27 17:30
*/
public class SqlUtil {
public static void runSql(Connection connection, String sql) throws SQLException {
Statement statement = null;
try {
statement = connection.createStatement();
statement.execute(sql);
} finally {
IoUtil.close(statement);
}
}
}

View File

@ -11,6 +11,7 @@ import com.qiaoba.api.system.entity.dto.DataScopeDto;
import com.qiaoba.api.system.entity.dto.SysRoleDto;
import com.qiaoba.api.system.entity.param.SysRoleParam;
import com.qiaoba.auth.utils.SecurityUtil;
import com.qiaoba.common.base.context.BaseContext;
import com.qiaoba.common.base.exceptions.ServiceException;
import com.qiaoba.common.database.entity.PageQuery;
import com.qiaoba.common.database.entity.TableDataInfo;

View File

@ -7,6 +7,7 @@ import com.qiaoba.common.base.constants.BaseConstant;
import com.qiaoba.common.base.constants.TenantConstant;
import com.qiaoba.common.base.context.BaseContext;
import com.qiaoba.common.database.config.DynamicDataSourceConfig;
import com.qiaoba.common.database.context.TenantDbTypeContext;
import com.qiaoba.common.web.utils.ResponseUtil;
import com.qiaoba.common.web.utils.UriUtil;
import com.qiaoba.module.tenant.entity.SysTenant;
@ -91,12 +92,12 @@ public class DynamicDataSourceFilter extends OncePerRequestFilter {
if (sysTenant.getMode().equals(SysTenant.DATASOURCE_MODE)) {
//设置当前租户对应的数据源
BaseContext.setDataSource(sysTenant.getTenantId());
BaseContext.setDatabaseType(DynamicDataSourceConfig.TENANT_DATASOURCE_TYPE_MAP.get(sysTenant.getTenantId()));
BaseContext.setDatabaseType(TenantDbTypeContext.get(sysTenant.getTenantId()));
}
// 字段模式 or Schema模式-数据源选择默认数据源
else {
BaseContext.setDataSource(TenantConstant.DEFAULT_TENANT_ID);
BaseContext.setDatabaseType(DynamicDataSourceConfig.TENANT_DATASOURCE_TYPE_MAP.get(TenantConstant.DEFAULT_TENANT_ID));
BaseContext.setDatabaseType(TenantDbTypeContext.getDefault());
}

View File

@ -1,13 +1,14 @@
package com.qiaoba.module.tenant.init.impl;
import cn.hutool.core.io.IoUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.db.sql.SqlExecutor;
import cn.hutool.http.HttpStatus;
import com.qiaoba.common.base.code.DatasourceErrorCode;
import com.qiaoba.common.database.utils.SqlUtil;
import com.qiaoba.common.database.context.TenantDbTypeContext;
import com.qiaoba.common.database.utils.DbUtil;
import com.qiaoba.module.tenant.entity.vo.TenantInitVo;
import com.qiaoba.module.tenant.init.InitTablesStrategy;
import com.qiaoba.module.tenant.utils.DbUtil;
import org.springframework.stereotype.Service;
import java.io.IOException;
@ -23,21 +24,32 @@ import java.sql.SQLException;
*/
@Service
public class MysqlInitTablesStrategy implements InitTablesStrategy {
public static final String CREATE_MYSQL_DB_SQL = "DROP DATABASE IF EXISTS `{}`;CREATE DATABASE `{}` CHARACTER SET 'utf8mb4' COLLATE 'utf8mb4_general_ci';";
@Override
public TenantInitVo create(Connection conn, String schema) {
// 切换 Schema
try {
SqlUtil.runSql(conn, StrUtil.format("use `{}`;", schema));
DbUtil.runScript(conn, "MySQL/table/base_tables");
conn.commit();
return new TenantInitVo(HttpStatus.HTTP_OK, null);
// 创建库
SqlExecutor.execute(conn, StrUtil.format(CREATE_MYSQL_DB_SQL, schema, schema));
} catch (SQLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
IoUtil.close(conn);
return new TenantInitVo(DatasourceErrorCode.CREATE_SCHEMA_ERROR.getCode(), e.getMessage());
}
try {
// 切换 Schema
DbUtil.setSchema(TenantDbTypeContext.getDefault(), conn, schema);
DbUtil.runScript(conn, "MySQL/table/base_tables");
return new TenantInitVo(HttpStatus.HTTP_OK, null);
} catch (SQLException e) {
return new TenantInitVo(DatasourceErrorCode.SWITCH_SCHEMA_ERROR.getCode(), e.getMessage());
} catch (IOException e) {
return new TenantInitVo(DatasourceErrorCode.CREATE_TABLE_ERROR.getCode(), e.getMessage());
} finally {
IoUtil.close(conn);
}
return new TenantInitVo(DatasourceErrorCode.CREATE_TABLE_ERROR.getCode(), null);
}
}

View File

@ -4,9 +4,10 @@ import cn.hutool.core.io.IoUtil;
import cn.hutool.http.HttpStatus;
import com.alibaba.druid.pool.DruidDataSource;
import com.qiaoba.common.base.code.DatasourceErrorCode;
import com.qiaoba.common.base.constants.TenantConstant;
import com.qiaoba.common.base.constants.BaseConstant;
import com.qiaoba.common.base.enums.DataBaseEnum;
import com.qiaoba.common.database.config.DynamicDataSourceConfig;
import com.qiaoba.common.database.context.PrimaryDatasourceContext;
import com.qiaoba.common.database.context.TenantDbTypeContext;
import com.qiaoba.common.database.utils.JdbcUtil;
import com.qiaoba.module.tenant.entity.SysTenant;
import com.qiaoba.module.tenant.entity.SysTenantDatasource;
@ -17,6 +18,7 @@ import com.qiaoba.module.tenant.service.SysTenantDatasourceService;
import com.qiaoba.module.tenant.service.SysTenantInitService;
import com.qiaoba.module.tenant.service.SysTenantService;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import java.sql.Connection;
@ -36,6 +38,8 @@ public class SysTenantInitServiceImpl implements SysTenantInitService {
private final SysTenantService sysTenantService;
private final SysTenantDatasourceService sysTenantDatasourceService;
@Value("${spring.application.name}")
private String schemaPrefix;
@Override
public TenantInitCheckVo check(String tenantId) {
@ -77,11 +81,11 @@ public class SysTenantInitServiceImpl implements SysTenantInitService {
if (SysTenant.SCHEMA_MODE.equals(sysTenant.getMode())) {
Connection connection = null;
try {
String schema = "qiaoba-boot-2";
String schema = schemaPrefix + BaseConstant.HYPHEN_JOIN_STR + tenantId;
// 获取主库Connection 和 Schema
DruidDataSource dataSource = (DruidDataSource) DynamicDataSourceConfig.PRIMARY_DATASOURCE_MAP.get(TenantConstant.DEFAULT_TENANT_ID);
DruidDataSource dataSource = (DruidDataSource) PrimaryDatasourceContext.getDefault();
connection = dataSource.getConnection();
return InitTablesStrategyFactory.getStrategy(DynamicDataSourceConfig.TENANT_DATASOURCE_TYPE_MAP.get(TenantConstant.DEFAULT_TENANT_ID)).create(connection, schema);
return InitTablesStrategyFactory.getStrategy(TenantDbTypeContext.getDefault()).create(connection, schema);
} catch (Exception e) {
e.printStackTrace();
} finally {