mirror of
https://gitee.com/dromara/Jpom.git
synced 2024-11-29 18:38:32 +08:00
🐞 fix(服务端): 无法查询到分组
This commit is contained in:
parent
6d982ab09c
commit
579fcfcc08
@ -37,7 +37,6 @@ import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
/**
|
||||
* 数据存储服务
|
||||
@ -70,9 +69,9 @@ public class StorageServiceFactory {
|
||||
/**
|
||||
* 将数据迁移到当前环境
|
||||
*/
|
||||
public static void migrateH2ToNow(DbExtConfig dbExtConfig, String h2Url, String h2User, String h2Pass,DbExtConfig.Mode targetNode) {
|
||||
public static void migrateH2ToNow(DbExtConfig dbExtConfig, String h2Url, String h2User, String h2Pass, DbExtConfig.Mode targetNode) {
|
||||
log.info("开始迁移 h2 数据到 {}", dbExtConfig.getMode());
|
||||
Assert.notNull(mode,"未指定目标数据库信息");
|
||||
Assert.notNull(mode, "未指定目标数据库信息");
|
||||
try {
|
||||
IStorageService h2StorageService = doCreateStorageService(DbExtConfig.Mode.H2);
|
||||
boolean hasDbData = h2StorageService.hasDbData();
|
||||
@ -101,20 +100,20 @@ public class StorageServiceFactory {
|
||||
log.info("成功连接 {} {}", dbExtConfig.getMode(), dbExtConfig.getUrl());
|
||||
Set<Class<?>> classes = ClassUtil.scanPackageByAnnotation("org.dromara.jpom", TableName.class);
|
||||
classes = classes.stream()
|
||||
.filter(aClass -> {
|
||||
TableName tableName = aClass.getAnnotation(TableName.class);
|
||||
DbExtConfig.Mode[] modes = tableName.modes();
|
||||
if (ArrayUtil.isEmpty(modes)) {
|
||||
return true;
|
||||
}
|
||||
return ArrayUtil.contains(modes, dbExtConfig.getMode());
|
||||
})
|
||||
.sorted((o1, o2) -> StrUtil.compare(o1.getSimpleName(), o2.getSimpleName(), false))
|
||||
.collect(Collectors.toCollection(LinkedHashSet::new));
|
||||
.filter(aClass -> {
|
||||
TableName tableName = aClass.getAnnotation(TableName.class);
|
||||
DbExtConfig.Mode[] modes = tableName.modes();
|
||||
if (ArrayUtil.isEmpty(modes)) {
|
||||
return true;
|
||||
}
|
||||
return ArrayUtil.contains(modes, dbExtConfig.getMode());
|
||||
})
|
||||
.sorted((o1, o2) -> StrUtil.compare(o1.getSimpleName(), o2.getSimpleName(), false))
|
||||
.collect(Collectors.toCollection(LinkedHashSet::new));
|
||||
log.info("准备迁移数据");
|
||||
int total = 0;
|
||||
for (Class<?> aClass : classes) {
|
||||
total += migrateH2ToNowItem(aClass, h2DsFactory, nowDsFactory,targetNode);
|
||||
total += migrateH2ToNowItem(aClass, h2DsFactory, nowDsFactory, targetNode);
|
||||
}
|
||||
long endTime = SystemClock.now();
|
||||
log.info("迁移完成,累计迁移 {} 条数据,耗时:{}", total, DateUtil.formatBetween(endTime - time));
|
||||
@ -128,7 +127,7 @@ public class StorageServiceFactory {
|
||||
}
|
||||
}
|
||||
|
||||
private static int migrateH2ToNowItem(Class<?> aClass, DSFactory h2DsFactory, DSFactory targetDsFactory,DbExtConfig.Mode targetNode) throws SQLException {
|
||||
private static int migrateH2ToNowItem(Class<?> aClass, DSFactory h2DsFactory, DSFactory targetDsFactory, DbExtConfig.Mode targetNode) throws SQLException {
|
||||
TableName tableName = aClass.getAnnotation(TableName.class);
|
||||
Wrapper targetModeWrapper = DialectUtil.getDialectByMode(targetNode).getWrapper();
|
||||
Set<String> boolFieldSet = Arrays.stream(ReflectUtil.getFields(aClass, field -> Boolean.class.equals(field.getType()) || boolean.class.equals(field.getType())))
|
||||
@ -140,7 +139,7 @@ public class StorageServiceFactory {
|
||||
while (true) {
|
||||
Entity where = Entity.create(tableName.value());
|
||||
PageResult<Entity> pageResult;
|
||||
Db db = Db.use(h2DsFactory.getDataSource(),DialectUtil.getH2Dialect());
|
||||
Db db = Db.use(h2DsFactory.getDataSource(), DialectUtil.getH2Dialect());
|
||||
Page page = new Page(1, 200);
|
||||
pageResult = db.page(where, page);
|
||||
if (pageResult.isEmpty()) {
|
||||
@ -154,12 +153,12 @@ public class StorageServiceFactory {
|
||||
Entity entity = Entity.create(targetModeWrapper.wrap(tableName.value()));
|
||||
return entity.parseBean(o, false, true);
|
||||
}).peek(entity -> {
|
||||
if( DbExtConfig.Mode.POSTGRESQL.equals(targetNode) ) {
|
||||
if (DbExtConfig.Mode.POSTGRESQL.equals(targetNode)) {
|
||||
// tinyint类型查出来是数字,需转为bool
|
||||
boolFieldSet.forEach(fieldName->{
|
||||
boolFieldSet.forEach(fieldName -> {
|
||||
Object field = entity.get(fieldName);
|
||||
if( field instanceof Number ) {
|
||||
entity.set(fieldName,BooleanUtil.toBoolean(field.toString()));
|
||||
if (field instanceof Number) {
|
||||
entity.set(fieldName, BooleanUtil.toBoolean(field.toString()));
|
||||
}
|
||||
});
|
||||
}
|
||||
@ -174,18 +173,18 @@ public class StorageServiceFactory {
|
||||
}
|
||||
total += newResult.size();
|
||||
// 插入信息数据
|
||||
Db db2 = Db.use(targetDsFactory.getDataSource(),DialectUtil.getDialectByMode(targetNode));
|
||||
Db db2 = Db.use(targetDsFactory.getDataSource(), DialectUtil.getDialectByMode(targetNode));
|
||||
|
||||
Connection connection = db2.getConnection();
|
||||
try {
|
||||
SqlConnRunner runner = db2.getRunner();
|
||||
for (Entity entity : newResult) {
|
||||
// hutool的批量insert方法有坑,可能导致部分参数被丢弃
|
||||
runner.insert(connection,entity);
|
||||
runner.insert(connection, entity);
|
||||
}
|
||||
}catch (Exception e){
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}finally {
|
||||
} finally {
|
||||
db2.closeConnection(connection);
|
||||
}
|
||||
|
||||
|
@ -9,8 +9,6 @@
|
||||
*/
|
||||
package org.dromara.jpom.dialect;
|
||||
|
||||
import cn.hutool.core.bean.BeanUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import cn.hutool.db.dialect.Dialect;
|
||||
import cn.hutool.db.dialect.impl.H2Dialect;
|
||||
import cn.hutool.db.dialect.impl.MysqlDialect;
|
||||
@ -19,10 +17,7 @@ import cn.hutool.db.sql.Wrapper;
|
||||
import cn.hutool.extra.spring.SpringUtil;
|
||||
import org.dromara.jpom.db.DbExtConfig;
|
||||
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
/**
|
||||
* 数据库方言工具类
|
||||
@ -34,12 +29,15 @@ public class DialectUtil {
|
||||
|
||||
private final static ConcurrentHashMap<DbExtConfig.Mode, Dialect> DIALECT_CACHE = new ConcurrentHashMap<>();
|
||||
private static volatile Wrapper currentDbFieldWrapper;
|
||||
private static final ConcurrentHashMap<String, String> WRAP_FIELD_MAP = new ConcurrentHashMap<>();
|
||||
/**
|
||||
* 通用的包裹器
|
||||
*/
|
||||
private static final Wrapper COMMON_WRAPPER = new Wrapper('`');
|
||||
|
||||
public static Dialect getH2Dialect() {
|
||||
return DIALECT_CACHE.computeIfAbsent(DbExtConfig.Mode.H2, key -> {
|
||||
H2Dialect h2Dialect = new H2Dialect();
|
||||
h2Dialect.setWrapper(new Wrapper('`'));
|
||||
h2Dialect.setWrapper(COMMON_WRAPPER);
|
||||
return h2Dialect;
|
||||
});
|
||||
}
|
||||
@ -55,28 +53,22 @@ public class DialectUtil {
|
||||
*/
|
||||
public static Dialect getPostgresqlDialect() {
|
||||
return DIALECT_CACHE.computeIfAbsent(DbExtConfig.Mode.POSTGRESQL, key -> {
|
||||
// 需要特殊处理的列名或表名,需要时在这里添加即可
|
||||
Set<String> names = Stream.of("group", "desc", "user", "content").map(String::toLowerCase).collect(Collectors.toSet());
|
||||
Wrapper wrapper = new Wrapper() {
|
||||
Wrapper wrapper = new Wrapper('"') {
|
||||
@Override
|
||||
public String wrap(String field) {
|
||||
field = field.toLowerCase();
|
||||
if (field.charAt(0) == '`' && field.charAt(field.length() - 1) == '`') {
|
||||
field = field.substring(1, field.length() - 1);
|
||||
}
|
||||
if (names.contains(field)) {
|
||||
return super.wrap(field);
|
||||
}
|
||||
return field; // 不属于names的直接返回
|
||||
// 代码中存在固定编码 warp
|
||||
String unWrap = COMMON_WRAPPER.unWrap(field);
|
||||
return super.wrap(unWrap);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String unWrap(String field) {
|
||||
String unWrap = COMMON_WRAPPER.unWrap(field);
|
||||
return super.unWrap(unWrap);
|
||||
}
|
||||
};
|
||||
|
||||
PostgresqlDialect dialect = new PostgresqlDialect();
|
||||
Wrapper innerWrapper = (Wrapper) BeanUtil.getFieldValue(dialect, "wrapper");
|
||||
|
||||
wrapper.setPreWrapQuote(innerWrapper.getPreWrapQuote());
|
||||
wrapper.setSufWrapQuote(innerWrapper.getSufWrapQuote());
|
||||
BeanUtil.setFieldValue(dialect, "wrapper", wrapper);
|
||||
dialect.setWrapper(wrapper);
|
||||
return dialect;
|
||||
});
|
||||
}
|
||||
@ -90,8 +82,9 @@ public class DialectUtil {
|
||||
return getMySqlDialect();
|
||||
case POSTGRESQL:
|
||||
return getPostgresqlDialect();
|
||||
default:
|
||||
throw new IllegalArgumentException("未知的数据库方言类型:" + mode);
|
||||
}
|
||||
throw new IllegalArgumentException("未知的数据库方言类型");
|
||||
}
|
||||
|
||||
/**
|
||||
@ -102,7 +95,7 @@ public class DialectUtil {
|
||||
*/
|
||||
public static String wrapField(String field) {
|
||||
initWrapFieldMap();
|
||||
return WRAP_FIELD_MAP.computeIfAbsent(field, key -> currentDbFieldWrapper.wrap(field));
|
||||
return currentDbFieldWrapper.wrap(field);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -125,24 +118,6 @@ public class DialectUtil {
|
||||
|
||||
public static String unWrapField(String field) {
|
||||
initWrapFieldMap();
|
||||
return WRAP_FIELD_MAP.computeIfAbsent(field, s -> {
|
||||
Character preWrapQuote = currentDbFieldWrapper.getPreWrapQuote();
|
||||
Character sufWrapQuote = currentDbFieldWrapper.getSufWrapQuote();
|
||||
if (preWrapQuote == null || sufWrapQuote == null || StrUtil.isBlank(s)) {
|
||||
return s;
|
||||
}
|
||||
|
||||
//如果已经包含包装的引号,返回原字符
|
||||
if (!StrUtil.isSurround(s, preWrapQuote, sufWrapQuote)) {
|
||||
return s;
|
||||
}
|
||||
|
||||
//如果字段中包含通配符或者括号(字段通配符或者函数),不做包装
|
||||
if (StrUtil.containsAnyIgnoreCase(s, "*", "(", " ", " as ")) {
|
||||
return s;
|
||||
}
|
||||
|
||||
return StrUtil.removeSuffix(StrUtil.removePrefix(s, preWrapQuote.toString()), sufWrapQuote.toString());
|
||||
});
|
||||
return currentDbFieldWrapper.unWrap(field);
|
||||
}
|
||||
}
|
||||
|
@ -23,6 +23,7 @@ import java.util.stream.Collectors;
|
||||
/**
|
||||
* postgresql的sql语句构建类
|
||||
* 目前不管列名还是表名,索引名,都会转化为小写的形式,而特殊的关键字会通过Dialect的Wrapper处理
|
||||
*
|
||||
* @author whz
|
||||
* @since 2024/3/10
|
||||
*/
|
||||
@ -36,7 +37,7 @@ public class PostgresqlTableBuilderImpl implements IStorageSqlBuilderService {
|
||||
public PostgresqlTableBuilderImpl() {
|
||||
Set<Class<?>> modelClassSet = ClassUtil.scanPackageByAnnotation("org.dromara.jpom", TableName.class);
|
||||
this.tableName2ModelBoolFieldNameSetMap = new HashMap<>();
|
||||
modelClassSet.forEach(modelClass->{
|
||||
modelClassSet.forEach(modelClass -> {
|
||||
TableName annotation = modelClass.getAnnotation(TableName.class);
|
||||
// 统一处理成小写,model也应该不会出现转为小写后重名的field
|
||||
String tableName = annotation.value().toLowerCase();
|
||||
@ -44,7 +45,7 @@ public class PostgresqlTableBuilderImpl implements IStorageSqlBuilderService {
|
||||
Set<String> nameSet = Arrays.stream(boolFieldArr)
|
||||
.map(field -> field.getName().toLowerCase())
|
||||
.collect(Collectors.toSet());
|
||||
tableName2ModelBoolFieldNameSetMap.put(tableName,nameSet);
|
||||
tableName2ModelBoolFieldNameSetMap.put(tableName, nameSet);
|
||||
});
|
||||
}
|
||||
|
||||
@ -73,7 +74,7 @@ public class PostgresqlTableBuilderImpl implements IStorageSqlBuilderService {
|
||||
* field需要通过wrapper处理
|
||||
*/
|
||||
switch (indexType) {
|
||||
case "ADD-UNIQUE":{
|
||||
case "ADD-UNIQUE": {
|
||||
Assert.notEmpty(fields, "索引未配置字段");
|
||||
stringBuilder.append("CALL drop_index_if_exists('").append(tableName).append("','").append(name).append("')").append(";").append(StrUtil.LF);
|
||||
stringBuilder.append(this.delimiter()).append(StrUtil.LF);
|
||||
@ -115,14 +116,14 @@ public class PostgresqlTableBuilderImpl implements IStorageSqlBuilderService {
|
||||
case "ADD":
|
||||
stringBuilder.append("CALL add_column_if_not_exists('").append(tableName).append("','")
|
||||
.append(columnName).append("','");
|
||||
stringBuilder.append(generateColumnSql(viewAlterData.getTableName(),viewAlterData,true));
|
||||
stringBuilder.append(generateColumnSql(viewAlterData.getTableName(), viewAlterData, true));
|
||||
stringBuilder.append("');");
|
||||
/**
|
||||
* 添加列时,因为不能同时指定注释内容,单独加一个语句设置注释
|
||||
* COMMENT ON COLUMN 表名.field IS '注释内容'
|
||||
* field需要通过wrapper处理
|
||||
*/
|
||||
if( StrUtil.isNotBlank(viewAlterData.getComment()) ){
|
||||
if (StrUtil.isNotBlank(viewAlterData.getComment())) {
|
||||
stringBuilder.append(delimiter()).append(StrUtil.LF);
|
||||
stringBuilder.append("COMMENT ON COLUMN ").append(tableName)
|
||||
.append(StrUtil.DOT).append(fieldWrapper.wrap(viewAlterData.getName())).append(" IS ")
|
||||
@ -160,13 +161,13 @@ public class PostgresqlTableBuilderImpl implements IStorageSqlBuilderService {
|
||||
stringBuilder.append("CREATE TABLE IF NOT EXISTS ").append(tableName).append(StrUtil.LF);
|
||||
stringBuilder.append("(").append(StrUtil.LF);
|
||||
for (TableViewData tableViewData : row) {
|
||||
stringBuilder.append(StrUtil.TAB).append(this.generateColumnSql(tableName,tableViewData)).append(StrUtil.COMMA).append(StrUtil.LF);
|
||||
stringBuilder.append(StrUtil.TAB).append(this.generateColumnSql(tableName, tableViewData)).append(StrUtil.COMMA).append(StrUtil.LF);
|
||||
}
|
||||
// 主键
|
||||
List<String> primaryKeys = row.stream()
|
||||
.filter(tableViewData -> tableViewData.getPrimaryKey() != null && tableViewData.getPrimaryKey())
|
||||
.map(viewData->fieldWrapper.wrap(viewData.getName()))
|
||||
.collect(Collectors.toList());
|
||||
.filter(tableViewData -> tableViewData.getPrimaryKey() != null && tableViewData.getPrimaryKey())
|
||||
.map(viewData -> fieldWrapper.wrap(viewData.getName()))
|
||||
.collect(Collectors.toList());
|
||||
Assert.notEmpty(primaryKeys, "表没有主键");
|
||||
stringBuilder.append(StrUtil.TAB).append("PRIMARY KEY (").append(CollUtil.join(primaryKeys, StrUtil.COMMA)).append(")").append(StrUtil.LF);
|
||||
stringBuilder.append(");").append(StrUtil.LF);
|
||||
@ -176,7 +177,7 @@ public class PostgresqlTableBuilderImpl implements IStorageSqlBuilderService {
|
||||
|
||||
// 建表语句的列注释需要通过单独的sql语句设置
|
||||
for (TableViewData tableViewData : row) {
|
||||
if( StrUtil.isNotBlank(tableViewData.getComment()) ) {
|
||||
if (StrUtil.isNotBlank(tableViewData.getComment())) {
|
||||
stringBuilder.append(delimiter()).append(StrUtil.LF);
|
||||
stringBuilder.append("CALL exec_if_column_exists('")
|
||||
.append(tableName).append("','")
|
||||
@ -196,11 +197,12 @@ public class PostgresqlTableBuilderImpl implements IStorageSqlBuilderService {
|
||||
|
||||
@Override
|
||||
public String generateColumnSql(String tableName, TableViewRowData tableViewRowData) {
|
||||
return generateColumnSql(tableName,tableViewRowData,false);
|
||||
return generateColumnSql(tableName, tableViewRowData, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成 alter add 或 create table 时的列定义
|
||||
*
|
||||
* @param tableName
|
||||
* @param tableViewRowData
|
||||
* @param encode
|
||||
@ -210,14 +212,14 @@ public class PostgresqlTableBuilderImpl implements IStorageSqlBuilderService {
|
||||
|
||||
StringBuilder strBuilder = new StringBuilder();
|
||||
Wrapper fieldWrapper = DialectUtil.getPostgresqlDialect().getWrapper();
|
||||
String type = getColumnTypeStr(tableName,tableViewRowData.getName(),
|
||||
tableViewRowData.getType(),tableViewRowData.getLen());
|
||||
String type = getColumnTypeStr(tableName, tableViewRowData.getName(),
|
||||
tableViewRowData.getType(), tableViewRowData.getLen());
|
||||
strBuilder.append(StrUtil.SPACE).append(fieldWrapper.wrap(tableViewRowData.getName()))
|
||||
.append(StrUtil.SPACE).append(type);
|
||||
|
||||
String defaultValue = tableViewRowData.getDefaultValue();
|
||||
if (StrUtil.isNotEmpty(defaultValue)) {
|
||||
if( "BOOLEAN".equals(type) ) {
|
||||
if ("BOOLEAN".equals(type)) {
|
||||
defaultValue = Boolean.toString(BooleanUtil.toBoolean(defaultValue.trim()));
|
||||
}
|
||||
strBuilder.append(" DEFAULT '").append(defaultValue).append("'");
|
||||
@ -237,6 +239,7 @@ public class PostgresqlTableBuilderImpl implements IStorageSqlBuilderService {
|
||||
/**
|
||||
* 生成postgresql的alter语句
|
||||
* postgresql不像 h2或mysql可以一个alter同时设置 数据类型,默认值,非空,注释,因此需生成多条sql语句才能实现功能
|
||||
*
|
||||
* @param viewAlterData
|
||||
* @return
|
||||
*/
|
||||
@ -248,8 +251,8 @@ public class PostgresqlTableBuilderImpl implements IStorageSqlBuilderService {
|
||||
String name = fieldWrapper.wrap(viewAlterData.getName());
|
||||
|
||||
// 先改类型
|
||||
String type = getColumnTypeStr(viewAlterData.getTableName(),viewAlterData.getName()
|
||||
,viewAlterData.getType(),viewAlterData.getLen());
|
||||
String type = getColumnTypeStr(viewAlterData.getTableName(), viewAlterData.getName()
|
||||
, viewAlterData.getType(), viewAlterData.getLen());
|
||||
strBuilder.append("ALTER TABLE ").append(tableName)
|
||||
.append(" ALTER COLUMN ").append(name)
|
||||
.append(" TYPE ").append(type).append(";");
|
||||
@ -261,11 +264,11 @@ public class PostgresqlTableBuilderImpl implements IStorageSqlBuilderService {
|
||||
.append(" ALTER COLUMN ").append(name)
|
||||
.append(" SET DEFAULT '");
|
||||
if (StrUtil.isNotEmpty(defaultValue)) {
|
||||
if( "BOOLEAN".equals(type) ) {
|
||||
if ("BOOLEAN".equals(type)) {
|
||||
defaultValue = Boolean.toString(BooleanUtil.toBoolean(defaultValue.trim()));
|
||||
}
|
||||
strBuilder.append(defaultValue).append("';");
|
||||
}else {
|
||||
} else {
|
||||
strBuilder.append("NULL").append("';");
|
||||
}
|
||||
|
||||
@ -276,7 +279,7 @@ public class PostgresqlTableBuilderImpl implements IStorageSqlBuilderService {
|
||||
Boolean notNull = viewAlterData.getNotNull();
|
||||
if (notNull != null && notNull) {
|
||||
strBuilder.append(" SET NOT NULL ").append(";");
|
||||
}else {
|
||||
} else {
|
||||
strBuilder.append(" DROP NOT NULL ").append(";");
|
||||
}
|
||||
|
||||
@ -293,14 +296,13 @@ public class PostgresqlTableBuilderImpl implements IStorageSqlBuilderService {
|
||||
}
|
||||
|
||||
|
||||
|
||||
@Override
|
||||
public String delimiter() {
|
||||
return "-- postgresql $delimiter$";
|
||||
}
|
||||
|
||||
|
||||
private String getColumnTypeStr(String tableName,String columnName,String type,Integer dataLen) {
|
||||
private String getColumnTypeStr(String tableName, String columnName, String type, Integer dataLen) {
|
||||
Assert.hasText(type, "未正确配置数据类型");
|
||||
type = type.toUpperCase();
|
||||
switch (type) {
|
||||
|
Loading…
Reference in New Issue
Block a user