add
This commit is contained in:
@ -1,13 +1,13 @@
|
|||||||
UPDATE sys_dept set tenant_id = '2';
|
UPDATE sys_dept set tenant_id = '1';
|
||||||
UPDATE sys_menu set tenant_id = '2';
|
UPDATE sys_menu set tenant_id = '1';
|
||||||
UPDATE sys_post set tenant_id = '2';
|
UPDATE sys_post set tenant_id = '1';
|
||||||
UPDATE sys_role set tenant_id = '2';
|
UPDATE sys_role set tenant_id = '1';
|
||||||
UPDATE sys_user set tenant_id = '2';
|
UPDATE sys_user set tenant_id = '1';
|
||||||
UPDATE sys_config set tenant_id = '2';
|
UPDATE sys_config set tenant_id = '1';
|
||||||
UPDATE sys_login_log set tenant_id = '2';
|
UPDATE sys_login_log set tenant_id = '1';
|
||||||
UPDATE sys_role_dept set tenant_id = '2';
|
UPDATE sys_role_dept set tenant_id = '1';
|
||||||
UPDATE sys_role_menu set tenant_id = '2';
|
UPDATE sys_role_menu set tenant_id = '1';
|
||||||
UPDATE sys_user_post set tenant_id = '2';
|
UPDATE sys_user_post set tenant_id = '1';
|
||||||
UPDATE sys_user_role set tenant_id = '2';
|
UPDATE sys_user_role set tenant_id = '1';
|
||||||
UPDATE sys_dict_data set tenant_id = '2';
|
UPDATE sys_dict_data set tenant_id = '1';
|
||||||
UPDATE sys_dict_type set tenant_id = '2';
|
UPDATE sys_dict_type set tenant_id = '1';
|
||||||
|
8
pom.xml
8
pom.xml
@ -47,8 +47,6 @@
|
|||||||
<mysql-connector.version>8.0.33</mysql-connector.version>
|
<mysql-connector.version>8.0.33</mysql-connector.version>
|
||||||
<!-- PgSql -->
|
<!-- PgSql -->
|
||||||
<pgsql.version>42.6.0</pgsql.version>
|
<pgsql.version>42.6.0</pgsql.version>
|
||||||
<!-- Oracle 11g -->
|
|
||||||
<oracle.version>23.2.0.0</oracle.version>
|
|
||||||
<!-- mybatis -->
|
<!-- mybatis -->
|
||||||
<mybatisplus-spring-boot.version>3.5.3.1</mybatisplus-spring-boot.version>
|
<mybatisplus-spring-boot.version>3.5.3.1</mybatisplus-spring-boot.version>
|
||||||
<!-- easy poi -->
|
<!-- easy poi -->
|
||||||
@ -115,12 +113,6 @@
|
|||||||
<artifactId>postgresql</artifactId>
|
<artifactId>postgresql</artifactId>
|
||||||
<version>${pgsql.version}</version>
|
<version>${pgsql.version}</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
<!-- Oracle 11g -->
|
|
||||||
<dependency>
|
|
||||||
<groupId>com.oracle.database.jdbc</groupId>
|
|
||||||
<artifactId>ojdbc8</artifactId>
|
|
||||||
<version>${oracle.version}</version>
|
|
||||||
</dependency>
|
|
||||||
<!-- mybatis plus -->
|
<!-- mybatis plus -->
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.baomidou</groupId>
|
<groupId>com.baomidou</groupId>
|
||||||
|
@ -1,20 +1,30 @@
|
|||||||
qiaoba:
|
qiaoba:
|
||||||
file-upload-path: C:/${spring.application.name}/uploadPath/
|
file-upload-path: C:/${spring.application.name}/uploadPath/
|
||||||
dataSources:
|
dataSources:
|
||||||
- driver: com.mysql.cj.jdbc.Driver
|
# - driver: com.mysql.cj.jdbc.Driver
|
||||||
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
|
# 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
|
# username: root
|
||||||
password: Root123456789.
|
# password: Root123456789.
|
||||||
#连接池初始化大小
|
# #连接池初始化大小
|
||||||
initial-size: 5
|
# initial-size: 5
|
||||||
#最小空闲线程数
|
# #最小空闲线程数
|
||||||
min-idle: 10
|
# min-idle: 10
|
||||||
#最大连接池数量
|
# #最大连接池数量
|
||||||
max-active: 20
|
# max-active: 20
|
||||||
- driver: com.mysql.cj.jdbc.Driver
|
# - driver: com.mysql.cj.jdbc.Driver
|
||||||
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
|
# 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
|
# username: root
|
||||||
password: Root123456789.
|
# password: Root123456789.
|
||||||
|
# #连接池初始化大小
|
||||||
|
# initial-size: 5
|
||||||
|
# #最小空闲线程数
|
||||||
|
# min-idle: 10
|
||||||
|
# #最大连接池数量
|
||||||
|
# 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
|
initial-size: 5
|
||||||
#最小空闲线程数
|
#最小空闲线程数
|
||||||
@ -22,16 +32,6 @@ qiaoba:
|
|||||||
#最大连接池数量
|
#最大连接池数量
|
||||||
max-active: 20
|
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:
|
mybatis-plus:
|
||||||
configuration:
|
configuration:
|
||||||
# 自动驼峰命名规则(camel case)映射
|
# 自动驼峰命名规则(camel case)映射
|
||||||
@ -42,7 +42,8 @@ mybatis-plus:
|
|||||||
# MyBatis 自动映射时未知列或未知属性处理策
|
# MyBatis 自动映射时未知列或未知属性处理策
|
||||||
# NONE:不做处理 WARNING:打印相关警告 FAILING:抛出异常和详细信息
|
# NONE:不做处理 WARNING:打印相关警告 FAILING:抛出异常和详细信息
|
||||||
autoMappingUnknownColumnBehavior: NONE
|
autoMappingUnknownColumnBehavior: NONE
|
||||||
#log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
|
# 控制台打印 SQL
|
||||||
|
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
|
||||||
|
|
||||||
logging:
|
logging:
|
||||||
level:
|
level:
|
||||||
|
@ -42,6 +42,40 @@ spring:
|
|||||||
max-active: 8
|
max-active: 8
|
||||||
# #连接池最大阻塞等待时间(使用负值表示没有限制)
|
# #连接池最大阻塞等待时间(使用负值表示没有限制)
|
||||||
max-wait: -1ms
|
max-wait: -1ms
|
||||||
|
datasource:
|
||||||
|
druid:
|
||||||
|
# 自己配置监控统计拦截的filter
|
||||||
|
filter:
|
||||||
|
# 开启druiddatasource的状态监控
|
||||||
|
stat:
|
||||||
|
enabled: true
|
||||||
|
# 开启慢sql监控,超过2s 就认为是慢sql,记录到日志中
|
||||||
|
log-slow-sql: true
|
||||||
|
slow-sql-millis: 2000
|
||||||
|
# 日志监控,使用slf4j 进行日志输出
|
||||||
|
slf4j:
|
||||||
|
enabled: true
|
||||||
|
statement-log-error-enabled: true
|
||||||
|
statement-create-after-log-enabled: false
|
||||||
|
statement-close-after-log-enabled: false
|
||||||
|
result-set-open-after-log-enabled: false
|
||||||
|
result-set-close-after-log-enabled: false
|
||||||
|
########## 配置WebStatFilter,用于采集web关联监控的数据 ##########
|
||||||
|
web-stat-filter:
|
||||||
|
enabled: true # 启动 StatFilter
|
||||||
|
url-pattern: /* # 过滤所有url
|
||||||
|
exclusions: "*.js,*.gif,*.jpg,*.png,*.css,*.ico,/druid/*" # 排除一些不必要的url
|
||||||
|
session-stat-enable: true # 开启session统计功能
|
||||||
|
session-stat-max-count: 1000 # session的最大个数,默认100
|
||||||
|
########## 配置StatViewServlet(监控页面),用于展示Druid的统计信息 ##########
|
||||||
|
stat-view-servlet:
|
||||||
|
enabled: true # 启用StatViewServlet
|
||||||
|
url-pattern: /druid/* # 访问内置监控页面的路径,内置监控页面的首页是/druid/index.html
|
||||||
|
reset-enable: false # 不允许清空统计数据,重新计算
|
||||||
|
login-username: root # 配置监控页面访问密码
|
||||||
|
login-password: root
|
||||||
|
# allow: 127.0.0.1 # 允许访问的地址,如果allow没有配置或者为空,则允许所有访问
|
||||||
|
# deny: # 拒绝访问的地址,deny优先于allow,如果在deny列表中,就算在allow列表中,也会被拒绝
|
||||||
|
|
||||||
qiaoba:
|
qiaoba:
|
||||||
auth:
|
auth:
|
||||||
|
@ -40,7 +40,12 @@ public enum DatasourceErrorCode {
|
|||||||
/**
|
/**
|
||||||
* 初始化数据错误
|
* 初始化数据错误
|
||||||
*/
|
*/
|
||||||
INIT_DATA_ERROR(50406, "初始化数据错误");
|
INIT_DATA_ERROR(50406, "初始化数据错误"),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* schema 不存在
|
||||||
|
*/
|
||||||
|
SCHEMA_NOT_EXIST_ERROR(50407, "SCHEMA: {} 不存在");
|
||||||
|
|
||||||
private final Integer code;
|
private final Integer code;
|
||||||
private final String msg;
|
private final String msg;
|
||||||
|
@ -26,14 +26,6 @@ public enum DataBaseEnum {
|
|||||||
"com.mysql.cj.jdbc.Driver",
|
"com.mysql.cj.jdbc.Driver",
|
||||||
"SELECT 1"),
|
"SELECT 1"),
|
||||||
|
|
||||||
/**
|
|
||||||
* Oracle
|
|
||||||
*/
|
|
||||||
ORACLE("Oracle",
|
|
||||||
"jdbc:oracle:thin:@//{}:{}/{}",
|
|
||||||
"oracle.jdbc.OracleDriver",
|
|
||||||
"SELECT 1 from DUAL"),
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* PostgreSQL
|
* PostgreSQL
|
||||||
*/
|
*/
|
||||||
|
@ -32,9 +32,6 @@ public class DatabaseUtil {
|
|||||||
} else if (DataBaseEnum.POSTGRE_SQL.getType().equals(databaseType)) {
|
} else if (DataBaseEnum.POSTGRE_SQL.getType().equals(databaseType)) {
|
||||||
// (select position(',100,' in ',0,100,101,')) <> 0
|
// (select position(',100,' in ',0,100,101,')) <> 0
|
||||||
return "(select position('," + var + ",' in ','||" + var2 + "||',')) <> 0";
|
return "(select position('," + var + ",' in ','||" + var2 + "||',')) <> 0";
|
||||||
} else if (DataBaseEnum.ORACLE.getType().equals(databaseType)) {
|
|
||||||
// instr(',0,100,101,' , ',100,') <> 0
|
|
||||||
return "instr(','||" + var2 + "||',' , '," + var + ",') <> 0";
|
|
||||||
}
|
}
|
||||||
// find_in_set(100 , '0,100,101')
|
// find_in_set(100 , '0,100,101')
|
||||||
return "find_in_set(" + var + " , " + var2 + ") <> 0";
|
return "find_in_set(" + var + " , " + var2 + ") <> 0";
|
||||||
|
@ -29,10 +29,6 @@
|
|||||||
<groupId>org.postgresql</groupId>
|
<groupId>org.postgresql</groupId>
|
||||||
<artifactId>postgresql</artifactId>
|
<artifactId>postgresql</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
|
||||||
<groupId>com.oracle.database.jdbc</groupId>
|
|
||||||
<artifactId>ojdbc8</artifactId>
|
|
||||||
</dependency>
|
|
||||||
<!-- mybatis plus -->
|
<!-- mybatis plus -->
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.baomidou</groupId>
|
<groupId>com.baomidou</groupId>
|
||||||
|
@ -170,6 +170,9 @@ public class DynamicDataSourceConfig {
|
|||||||
dataSource.setMaxActive(dynamicDataSource.getMaxActive());
|
dataSource.setMaxActive(dynamicDataSource.getMaxActive());
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
dataSource.addFilters("stat");
|
||||||
|
// wall 防火墙 切勿开启, 开启后 导入SQL 会失败
|
||||||
|
// dataSource.addFilters("wall")
|
||||||
// 初始化数据源
|
// 初始化数据源
|
||||||
dataSource.init();
|
dataSource.init();
|
||||||
return dataSource;
|
return dataSource;
|
||||||
|
@ -62,4 +62,5 @@ public class MybatisPlusConfig {
|
|||||||
public IdentifierGenerator idGenerator() {
|
public IdentifierGenerator idGenerator() {
|
||||||
return new DefaultIdentifierGenerator(NetUtil.getLocalhost());
|
return new DefaultIdentifierGenerator(NetUtil.getLocalhost());
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -3,9 +3,13 @@ package com.qiaoba.common.database.factories;
|
|||||||
import com.qiaoba.common.database.config.DynamicDataSourceConfig;
|
import com.qiaoba.common.database.config.DynamicDataSourceConfig;
|
||||||
import com.qiaoba.common.database.context.DynamicDataSourceContext;
|
import com.qiaoba.common.database.context.DynamicDataSourceContext;
|
||||||
import com.qiaoba.common.database.properties.DataSourceProperties;
|
import com.qiaoba.common.database.properties.DataSourceProperties;
|
||||||
|
import com.qiaoba.common.database.properties.TenantSchema;
|
||||||
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
import org.springframework.context.annotation.Bean;
|
import org.springframework.context.annotation.Bean;
|
||||||
import org.springframework.context.annotation.Configuration;
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
|
||||||
|
import javax.annotation.PostConstruct;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 动态数据源工厂
|
* 动态数据源工厂
|
||||||
*
|
*
|
||||||
@ -16,6 +20,13 @@ import org.springframework.context.annotation.Configuration;
|
|||||||
@Configuration
|
@Configuration
|
||||||
public class DynamicDataSourceFactory {
|
public class DynamicDataSourceFactory {
|
||||||
|
|
||||||
|
@Value("${spring.application.name}")
|
||||||
|
private String schemaPrefix;
|
||||||
|
|
||||||
|
@PostConstruct
|
||||||
|
public void setSchemaPrefix() {
|
||||||
|
TenantSchema.setSchemaPrefix(schemaPrefix);
|
||||||
|
}
|
||||||
@Bean
|
@Bean
|
||||||
public DynamicDataSourceContext dataSource() {
|
public DynamicDataSourceContext dataSource() {
|
||||||
return new DynamicDataSourceContext();
|
return new DynamicDataSourceContext();
|
||||||
|
@ -2,6 +2,7 @@ package com.qiaoba.common.database.interceptors;
|
|||||||
|
|
||||||
import com.baomidou.mybatisplus.extension.plugins.inner.InnerInterceptor;
|
import com.baomidou.mybatisplus.extension.plugins.inner.InnerInterceptor;
|
||||||
import com.qiaoba.common.base.context.BaseContext;
|
import com.qiaoba.common.base.context.BaseContext;
|
||||||
|
import com.qiaoba.common.base.enums.DataBaseEnum;
|
||||||
import com.qiaoba.common.database.context.TenantDbTypeContext;
|
import com.qiaoba.common.database.context.TenantDbTypeContext;
|
||||||
import com.qiaoba.common.database.properties.TenantSchema;
|
import com.qiaoba.common.database.properties.TenantSchema;
|
||||||
import com.qiaoba.common.database.utils.DbUtil;
|
import com.qiaoba.common.database.utils.DbUtil;
|
||||||
@ -25,11 +26,12 @@ public class SchemaInterceptor implements InnerInterceptor {
|
|||||||
@Override
|
@Override
|
||||||
public void beforePrepare(StatementHandler sh, Connection conn, Integer transactionTimeout) {
|
public void beforePrepare(StatementHandler sh, Connection conn, Integer transactionTimeout) {
|
||||||
|
|
||||||
|
// SCHEMA 模式
|
||||||
if (Objects.nonNull(BaseContext.isSchemaMode()) && BaseContext.isSchemaMode()) {
|
if (Objects.nonNull(BaseContext.isSchemaMode()) && BaseContext.isSchemaMode()) {
|
||||||
try {
|
try {
|
||||||
DbUtil.setSchema(TenantDbTypeContext.getDefault(), conn, TenantSchema.getSchema(BaseContext.getTenantId()));
|
DbUtil.setSchema(TenantDbTypeContext.getDefault(), conn, TenantSchema.getSchema(BaseContext.getTenantId()));
|
||||||
} catch (SQLException e) {
|
} catch (SQLException e) {
|
||||||
log.info("切换SCHEMA失败, 原因: {}", e.getMessage());
|
log.error("切换SCHEMA失败, 原因: {}", e.getMessage());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
package com.qiaoba.common.database.properties;
|
package com.qiaoba.common.database.properties;
|
||||||
|
|
||||||
import com.qiaoba.common.base.constants.BaseConstant;
|
import com.qiaoba.common.base.constants.BaseConstant;
|
||||||
import org.springframework.beans.factory.annotation.Value;
|
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -17,8 +16,7 @@ public class TenantSchema {
|
|||||||
|
|
||||||
private static String schemaPrefix;
|
private static String schemaPrefix;
|
||||||
|
|
||||||
@Value("${spring.application.name}")
|
public static void setSchemaPrefix(String name) {
|
||||||
public void setSchemaPrefix(String name) {
|
|
||||||
schemaPrefix = name;
|
schemaPrefix = name;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
package com.qiaoba.common.database.utils;
|
package com.qiaoba.common.database.utils;
|
||||||
|
|
||||||
import cn.hutool.core.io.IoUtil;
|
import cn.hutool.core.io.IoUtil;
|
||||||
|
import cn.hutool.core.util.StrUtil;
|
||||||
import com.qiaoba.common.base.enums.DataBaseEnum;
|
import com.qiaoba.common.base.enums.DataBaseEnum;
|
||||||
import org.apache.ibatis.jdbc.ScriptRunner;
|
import org.apache.ibatis.jdbc.ScriptRunner;
|
||||||
import org.postgresql.jdbc.PgConnection;
|
import org.postgresql.jdbc.PgConnection;
|
||||||
@ -10,6 +11,7 @@ import java.io.File;
|
|||||||
import java.io.FileReader;
|
import java.io.FileReader;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.sql.Connection;
|
import java.sql.Connection;
|
||||||
|
import java.sql.ResultSet;
|
||||||
import java.sql.SQLException;
|
import java.sql.SQLException;
|
||||||
import java.sql.Statement;
|
import java.sql.Statement;
|
||||||
|
|
||||||
@ -20,12 +22,16 @@ import java.sql.Statement;
|
|||||||
*/
|
*/
|
||||||
public class DbUtil {
|
public class DbUtil {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* PgSQL 查询 schema 是否存在
|
||||||
|
*/
|
||||||
|
private static final String PGSQL_CHECK_SCHEMA_EXIST_SQL = "SELECT count(1) FROM information_schema.schemata WHERE schema_name = '{}'";
|
||||||
|
|
||||||
|
|
||||||
public static void setSchema(String dbType, Connection conn, String schema) throws SQLException {
|
public static void setSchema(String dbType, Connection conn, String schema) throws SQLException {
|
||||||
|
|
||||||
if (DataBaseEnum.MY_SQL.getType().equals(dbType)) {
|
if (DataBaseEnum.MY_SQL.getType().equals(dbType)) {
|
||||||
conn.setSchema(schema);
|
conn.setSchema(schema);
|
||||||
} else if (DataBaseEnum.ORACLE.getType().equals(dbType)) {
|
|
||||||
conn.setSchema(schema);
|
|
||||||
} else if (DataBaseEnum.POSTGRE_SQL.getType().equals(dbType)) {
|
} else if (DataBaseEnum.POSTGRE_SQL.getType().equals(dbType)) {
|
||||||
conn.unwrap(PgConnection.class).setSchema(schema);
|
conn.unwrap(PgConnection.class).setSchema(schema);
|
||||||
} else if (DataBaseEnum.SQL_SERVER.getType().equals(dbType)) {
|
} else if (DataBaseEnum.SQL_SERVER.getType().equals(dbType)) {
|
||||||
@ -33,6 +39,23 @@ public class DbUtil {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static Boolean checkSchema(String dbType, Connection conn, String schema) throws Exception {
|
||||||
|
if (DataBaseEnum.POSTGRE_SQL.getType().equals(dbType)) {
|
||||||
|
Statement statement = null;
|
||||||
|
try {
|
||||||
|
statement = conn.createStatement();
|
||||||
|
ResultSet resultSet = statement.executeQuery(StrUtil.format(PGSQL_CHECK_SCHEMA_EXIST_SQL, schema));
|
||||||
|
resultSet.next();
|
||||||
|
return resultSet.getInt(1) > 0;
|
||||||
|
|
||||||
|
} finally {
|
||||||
|
IoUtil.close(statement);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
public static void runScript(Connection conn, String filePath) throws IOException {
|
public static void runScript(Connection conn, String filePath) throws IOException {
|
||||||
ClassPathResource resource = new ClassPathResource(filePath);
|
ClassPathResource resource = new ClassPathResource(filePath);
|
||||||
File file = resource.getFile();
|
File file = resource.getFile();
|
||||||
@ -53,4 +76,21 @@ public class DbUtil {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void main(String[] args) {
|
||||||
|
Connection connection = null;
|
||||||
|
try {
|
||||||
|
connection = JdbcUtil.getConnection(
|
||||||
|
DataBaseEnum.getDriver("Oracle"),
|
||||||
|
"jdbc:oracle:thin:@//192.168.0.205:1521/ORCL",
|
||||||
|
"system",
|
||||||
|
"root"
|
||||||
|
);
|
||||||
|
setSchema("Oracle", connection, "QIAOBA1");
|
||||||
|
runSql(connection, "delete FROM SYS_USER where user_id = '1'");
|
||||||
|
} catch (SQLException e) {
|
||||||
|
System.out.println(e.getMessage());
|
||||||
|
} finally {
|
||||||
|
IoUtil.close(connection);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -4,8 +4,6 @@ import cn.hutool.core.io.IoUtil;
|
|||||||
import cn.hutool.core.util.StrUtil;
|
import cn.hutool.core.util.StrUtil;
|
||||||
import com.qiaoba.common.base.enums.DataBaseEnum;
|
import com.qiaoba.common.base.enums.DataBaseEnum;
|
||||||
import com.qiaoba.common.base.exceptions.ServiceException;
|
import com.qiaoba.common.base.exceptions.ServiceException;
|
||||||
import lombok.AllArgsConstructor;
|
|
||||||
import lombok.Data;
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
|
||||||
import java.sql.Connection;
|
import java.sql.Connection;
|
||||||
@ -71,36 +69,22 @@ public class JdbcUtil {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static Connection getConnection(String driver, String url, String username, String password) {
|
public static Connection getConnection(String driver, String url, String username, String password) {
|
||||||
Connection conn = null;
|
|
||||||
try {
|
try {
|
||||||
Class.forName(driver);
|
Class.forName(driver);
|
||||||
//建立连接
|
return DriverManager.getConnection(url, username, password);
|
||||||
conn = DriverManager.getConnection(url, username, password);
|
|
||||||
return conn;
|
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
throw new ServiceException(StrUtil.format("数据源连接失败,错误: {}", e.getMessage()));
|
throw new ServiceException(StrUtil.format("数据源连接失败,错误: {}", e.getMessage()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static CheckResult check(String driver, String url, String username, String password) {
|
public static Connection connection(String driver, String url, String username, String password) throws Exception {
|
||||||
Connection conn = null;
|
|
||||||
try {
|
|
||||||
Class.forName(driver);
|
Class.forName(driver);
|
||||||
//建立连接
|
return DriverManager.getConnection(url, username, password);
|
||||||
conn = DriverManager.getConnection(url, username, password);
|
|
||||||
return new CheckResult(true, null);
|
|
||||||
} catch (Exception e) {
|
|
||||||
return new CheckResult(false, e.getMessage());
|
|
||||||
} finally {
|
|
||||||
IoUtil.close(conn);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Data
|
|
||||||
@AllArgsConstructor
|
|
||||||
public static class CheckResult {
|
|
||||||
private boolean result;
|
|
||||||
private String msg;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
public static void main(String[] args) throws Exception {
|
||||||
|
Connection connection = getConnection("oracle.jdbc.OracleDriver", "jdbc:oracle:thin:@//192.168.0.205:1521/ORCL", "QIAOBA-BOOT-1", "123456");
|
||||||
|
DbUtil.runSql(connection, "delete from sys_post where post_id = '1'");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
|
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
|
||||||
com.qiaoba.common.database.factories.DynamicDataSourceFactory,\
|
com.qiaoba.common.database.factories.DynamicDataSourceFactory,\
|
||||||
com.qiaoba.common.database.properties.TenantSchema,\
|
|
||||||
com.qiaoba.common.database.config.MybatisPlusConfig
|
com.qiaoba.common.database.config.MybatisPlusConfig
|
||||||
|
@ -20,6 +20,7 @@ public class ResponseUtil {
|
|||||||
public static void response(HttpServletResponse response, String msg) throws IOException {
|
public static void response(HttpServletResponse response, String msg) throws IOException {
|
||||||
response.setStatus(HttpServletResponse.SC_OK);
|
response.setStatus(HttpServletResponse.SC_OK);
|
||||||
response.setContentType(ContentType.JSON.getValue());
|
response.setContentType(ContentType.JSON.getValue());
|
||||||
|
response.setCharacterEncoding("UTF-8");
|
||||||
PrintWriter writer = response.getWriter();
|
PrintWriter writer = response.getWriter();
|
||||||
writer.write(msg);
|
writer.write(msg);
|
||||||
writer.close();
|
writer.close();
|
||||||
|
@ -51,18 +51,20 @@ public class DynamicDataSourceFilter extends OncePerRequestFilter {
|
|||||||
"/**/*.html", "/**/*.css", "/**/*.js",
|
"/**/*.html", "/**/*.css", "/**/*.js",
|
||||||
// Knife4j
|
// Knife4j
|
||||||
"/swagger-resources", "/v3/api-docs/**", "/favicon.ico",
|
"/swagger-resources", "/v3/api-docs/**", "/favicon.ico",
|
||||||
|
// Druid 可视化web监控
|
||||||
|
"/druid/**",
|
||||||
// File
|
// File
|
||||||
BaseConstant.RESOURCE_PATTERN);
|
BaseConstant.RESOURCE_PATTERN);
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
|
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
|
||||||
|
try {
|
||||||
log.debug("Start run DynamicDataSourceFilter, Uri: {}", request.getRequestURI());
|
log.debug("Start run DynamicDataSourceFilter, Uri: {}", request.getRequestURI());
|
||||||
String tenantId = request.getHeader(TenantConstant.HEADER_KEY_TENANT);
|
String tenantId = request.getHeader(TenantConstant.HEADER_KEY_TENANT);
|
||||||
// 主系统 or 登录入口获取租户列表
|
// 主系统 or 登录入口获取租户列表
|
||||||
if (TenantConstant.DEFAULT_TENANT_ID.equals(tenantId) || TenantConstant.LOGIN_TENANT_LIST_URI.equals(request.getRequestURI())) {
|
if (TenantConstant.DEFAULT_TENANT_ID.equals(tenantId) || TenantConstant.LOGIN_TENANT_LIST_URI.equals(request.getRequestURI())) {
|
||||||
dynamicDataSourceConfig.setDefaultSetting();
|
dynamicDataSourceConfig.setDefaultSetting();
|
||||||
filterChain.doFilter(request, response);
|
filterChain.doFilter(request, response);
|
||||||
after();
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -82,8 +84,10 @@ public class DynamicDataSourceFilter extends OncePerRequestFilter {
|
|||||||
// 设置租户信息
|
// 设置租户信息
|
||||||
before(sysTenant);
|
before(sysTenant);
|
||||||
filterChain.doFilter(request, response);
|
filterChain.doFilter(request, response);
|
||||||
|
} finally {
|
||||||
after();
|
after();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void before(SysTenant sysTenant) {
|
private void before(SysTenant sysTenant) {
|
||||||
log.debug("设置租户信息, 租户ID: {},租户模式: {}", sysTenant.getTenantId(), sysTenant.getMode());
|
log.debug("设置租户信息, 租户ID: {},租户模式: {}", sysTenant.getTenantId(), sysTenant.getMode());
|
||||||
@ -143,7 +147,6 @@ public class DynamicDataSourceFilter extends OncePerRequestFilter {
|
|||||||
// 更新租户状态为已过期
|
// 更新租户状态为已过期
|
||||||
dynamicDataSourceConfig.setDefaultSetting();
|
dynamicDataSourceConfig.setDefaultSetting();
|
||||||
sysTenantService.updateStatus(sysTenant.getTenantId(), TenantStatusEnum.EXPIRE.getStatus());
|
sysTenantService.updateStatus(sysTenant.getTenantId(), TenantStatusEnum.EXPIRE.getStatus());
|
||||||
after();
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
|
@ -25,7 +25,7 @@ import java.sql.SQLException;
|
|||||||
@Service
|
@Service
|
||||||
public class MysqlInitTablesStrategy implements InitTablesStrategy {
|
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';";
|
public static final String CREATE_MYSQL_DB_SQL = "CREATE DATABASE `{}` CHARACTER SET 'utf8mb4' COLLATE 'utf8mb4_general_ci';";
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public TenantInitVo create(Connection conn, String schema) {
|
public TenantInitVo create(Connection conn, String schema) {
|
||||||
|
@ -1,8 +1,10 @@
|
|||||||
package com.qiaoba.module.tenant.init.impl;
|
package com.qiaoba.module.tenant.init.impl;
|
||||||
|
|
||||||
import cn.hutool.core.io.IoUtil;
|
import cn.hutool.core.io.IoUtil;
|
||||||
|
import cn.hutool.core.util.StrUtil;
|
||||||
import cn.hutool.http.HttpStatus;
|
import cn.hutool.http.HttpStatus;
|
||||||
import com.qiaoba.common.base.code.DatasourceErrorCode;
|
import com.qiaoba.common.base.code.DatasourceErrorCode;
|
||||||
|
import com.qiaoba.common.base.enums.DataBaseEnum;
|
||||||
import com.qiaoba.common.database.utils.DbUtil;
|
import com.qiaoba.common.database.utils.DbUtil;
|
||||||
import com.qiaoba.module.tenant.entity.vo.TenantInitVo;
|
import com.qiaoba.module.tenant.entity.vo.TenantInitVo;
|
||||||
import com.qiaoba.module.tenant.init.InitTablesStrategy;
|
import com.qiaoba.module.tenant.init.InitTablesStrategy;
|
||||||
@ -10,6 +12,7 @@ import org.springframework.stereotype.Service;
|
|||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.sql.Connection;
|
import java.sql.Connection;
|
||||||
|
import java.sql.SQLException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 初始化表策略-Mysql
|
* 初始化表策略-Mysql
|
||||||
@ -21,11 +24,22 @@ import java.sql.Connection;
|
|||||||
@Service
|
@Service
|
||||||
public class PgSqlInitTablesStrategy implements InitTablesStrategy {
|
public class PgSqlInitTablesStrategy implements InitTablesStrategy {
|
||||||
|
|
||||||
public static final String CREATE_MYSQL_DB_SQL = "DROP DATABASE IF EXISTS `{}`;CREATE DATABASE `{}` CHARACTER SET 'utf8mb4' COLLATE 'utf8mb4_general_ci';";
|
private static final String CREATE_PGSQL_SCHEMA_SQL = "CREATE SCHEMA \"{}\";";
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public TenantInitVo create(Connection conn, String schema) {
|
public TenantInitVo create(Connection conn, String schema) {
|
||||||
return null;
|
try {
|
||||||
|
// 新建模式
|
||||||
|
DbUtil.runSql(conn, StrUtil.format(CREATE_PGSQL_SCHEMA_SQL, schema));
|
||||||
|
// 切换模式
|
||||||
|
DbUtil.setSchema(DataBaseEnum.POSTGRE_SQL.getType(), conn, schema);
|
||||||
|
// 执行SQL
|
||||||
|
return create(conn);
|
||||||
|
} catch (SQLException e) {
|
||||||
|
return new TenantInitVo(DatasourceErrorCode.CREATE_SCHEMA_ERROR.getCode(), e.getMessage());
|
||||||
|
} finally {
|
||||||
|
IoUtil.close(conn);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -97,7 +97,7 @@ public class SysTenantDatasourceServiceImpl implements SysTenantDatasourceServic
|
|||||||
int result = updateById(datasource);
|
int result = updateById(datasource);
|
||||||
// 刷新PrimaryDatasourceMap
|
// 刷新PrimaryDatasourceMap
|
||||||
if (result > BaseConstant.HANDLE_ERROR) {
|
if (result > BaseConstant.HANDLE_ERROR) {
|
||||||
|
// todo
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
package com.qiaoba.module.tenant.service.impl;
|
package com.qiaoba.module.tenant.service.impl;
|
||||||
|
|
||||||
import cn.hutool.core.io.IoUtil;
|
import cn.hutool.core.io.IoUtil;
|
||||||
|
import cn.hutool.core.util.StrUtil;
|
||||||
import cn.hutool.http.HttpStatus;
|
import cn.hutool.http.HttpStatus;
|
||||||
import com.alibaba.druid.pool.DruidDataSource;
|
import com.alibaba.druid.pool.DruidDataSource;
|
||||||
import com.qiaoba.common.base.code.DatasourceErrorCode;
|
import com.qiaoba.common.base.code.DatasourceErrorCode;
|
||||||
@ -56,13 +57,27 @@ public class SysTenantInitServiceImpl implements SysTenantInitService {
|
|||||||
if (Objects.isNull(datasource)) {
|
if (Objects.isNull(datasource)) {
|
||||||
return new TenantInitCheckVo(sysTenant.getCompanyName(), sysTenant.getMode(), DatasourceErrorCode.NOT_FIND.getCode(), DatasourceErrorCode.NOT_FIND.getMsg());
|
return new TenantInitCheckVo(sysTenant.getCompanyName(), sysTenant.getMode(), DatasourceErrorCode.NOT_FIND.getCode(), DatasourceErrorCode.NOT_FIND.getMsg());
|
||||||
}
|
}
|
||||||
// 5. 有数据源, 检查连接性
|
|
||||||
JdbcUtil.CheckResult connectResult = JdbcUtil.check(DataBaseEnum.getDriver(datasource.getType()),
|
Connection connection = null;
|
||||||
|
try {
|
||||||
|
connection = JdbcUtil.connection(DataBaseEnum.getDriver(datasource.getType()),
|
||||||
DataBaseEnum.getUrl(datasource.getType(), datasource.getIp(), datasource.getPort(), datasource.getDbName(), datasource.getSchemaName()),
|
DataBaseEnum.getUrl(datasource.getType(), datasource.getIp(), datasource.getPort(), datasource.getDbName(), datasource.getSchemaName()),
|
||||||
datasource.getUsername(), datasource.getPassword());
|
datasource.getUsername(), datasource.getPassword());
|
||||||
if (!connectResult.isResult()) {
|
|
||||||
|
// 检查 SCHEMA 是否存在
|
||||||
|
if (StrUtil.isNotBlank(datasource.getSchemaName())) {
|
||||||
|
Boolean schemaExist = DbUtil.checkSchema(datasource.getType(), connection, datasource.getSchemaName());
|
||||||
|
if (!schemaExist) {
|
||||||
// 6. 数据源无法连接, 返回
|
// 6. 数据源无法连接, 返回
|
||||||
return new TenantInitCheckVo(sysTenant.getCompanyName(), sysTenant.getMode(), datasource, DatasourceErrorCode.CONNECT_ERROR.getCode(), connectResult.getMsg());
|
return new TenantInitCheckVo(sysTenant.getCompanyName(), sysTenant.getMode(), datasource,
|
||||||
|
DatasourceErrorCode.SCHEMA_NOT_EXIST_ERROR.getCode(), StrUtil.format(DatasourceErrorCode.SCHEMA_NOT_EXIST_ERROR.getMsg(), datasource.getSchemaName()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
// 6. 数据源无法连接, 返回
|
||||||
|
return new TenantInitCheckVo(sysTenant.getCompanyName(), sysTenant.getMode(), datasource, DatasourceErrorCode.CONNECT_ERROR.getCode(), e.getMessage());
|
||||||
|
} finally {
|
||||||
|
IoUtil.close(connection);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 7. 全部正常
|
// 7. 全部正常
|
||||||
@ -86,7 +101,8 @@ public class SysTenantInitServiceImpl implements SysTenantInitService {
|
|||||||
try {
|
try {
|
||||||
// 获取主库Connection 和 Schema
|
// 获取主库Connection 和 Schema
|
||||||
DruidDataSource dataSource = (DruidDataSource) PrimaryDatasourceContext.getDefault();
|
DruidDataSource dataSource = (DruidDataSource) PrimaryDatasourceContext.getDefault();
|
||||||
connection = dataSource.getConnection();
|
// 创建新的连接
|
||||||
|
connection = JdbcUtil.getConnection(dataSource.getDriverClassName(), dataSource.getUrl(), dataSource.getUsername(), dataSource.getPassword());
|
||||||
return InitTablesStrategyFactory.getStrategy(TenantDbTypeContext.getDefault()).create(connection, TenantSchema.getSchema(tenantId));
|
return InitTablesStrategyFactory.getStrategy(TenantDbTypeContext.getDefault()).create(connection, TenantSchema.getSchema(tenantId));
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
@ -112,19 +128,16 @@ public class SysTenantInitServiceImpl implements SysTenantInitService {
|
|||||||
if (TenantModeEnum.COLUMN.getMode().equals(sysTenant.getMode())) {
|
if (TenantModeEnum.COLUMN.getMode().equals(sysTenant.getMode())) {
|
||||||
// 获取默认租户的主数据源
|
// 获取默认租户的主数据源
|
||||||
DataSource dataSource = (DataSource) PrimaryDatasourceContext.getDefault();
|
DataSource dataSource = (DataSource) PrimaryDatasourceContext.getDefault();
|
||||||
// 获取默认租户的主数据库类型
|
|
||||||
String dbType = TenantDbTypeContext.getDefault();
|
|
||||||
// 初始化
|
// 初始化
|
||||||
return init(dataSource.getConnection(), tenantId);
|
return init(dataSource.getConnection(), tenantId);
|
||||||
}
|
}
|
||||||
// SCHEMA
|
// SCHEMA
|
||||||
else if (TenantModeEnum.SCHEMA.getMode().equals(sysTenant.getMode())) {
|
else if (TenantModeEnum.SCHEMA.getMode().equals(sysTenant.getMode())) {
|
||||||
// 获取默认租户的主数据源
|
// 获取主库Connection 和 Schema
|
||||||
DataSource dataSource = (DataSource) PrimaryDatasourceContext.getDefault();
|
DruidDataSource dataSource = (DruidDataSource) PrimaryDatasourceContext.getDefault();
|
||||||
// 获取默认租户的主数据库类型
|
// 创建新的连接
|
||||||
|
Connection connection = JdbcUtil.getConnection(dataSource.getDriverClassName(), dataSource.getUrl(), dataSource.getUsername(), dataSource.getPassword());
|
||||||
String dbType = TenantDbTypeContext.getDefault();
|
String dbType = TenantDbTypeContext.getDefault();
|
||||||
// 切换 SCHEMA
|
|
||||||
Connection connection = dataSource.getConnection();
|
|
||||||
DbUtil.setSchema(dbType, connection, TenantSchema.getSchema(tenantId));
|
DbUtil.setSchema(dbType, connection, TenantSchema.getSchema(tenantId));
|
||||||
// 初始化
|
// 初始化
|
||||||
return init(connection, tenantId);
|
return init(connection, tenantId);
|
||||||
|
Reference in New Issue
Block a user