💩 重构抽象层次;解决资源泄漏;优化元数据获取性能

This commit is contained in:
Bunny 2025-07-01 15:17:56 +08:00
parent 5ef135de32
commit 1e07831818
10 changed files with 102 additions and 112 deletions

View File

@ -1,6 +1,6 @@
package cn.bunny.controller; package cn.bunny.controller;
import cn.bunny.core.factory.ConcreteSqlParserDatabaseInfoService; import cn.bunny.core.factory.SqlMetadataProvider;
import cn.bunny.domain.entity.ColumnMetaData; import cn.bunny.domain.entity.ColumnMetaData;
import cn.bunny.domain.entity.TableMetaData; import cn.bunny.domain.entity.TableMetaData;
import cn.bunny.domain.result.Result; import cn.bunny.domain.result.Result;
@ -19,7 +19,7 @@ import java.util.List;
@RequiredArgsConstructor @RequiredArgsConstructor
public class SqlParserController { public class SqlParserController {
private final ConcreteSqlParserDatabaseInfoService sqlParserService; private final SqlMetadataProvider sqlParserService;
@Operation(summary = "解析SQL成表信息", description = "解析SQL成表信息") @Operation(summary = "解析SQL成表信息", description = "解析SQL成表信息")
@PostMapping("tableInfo") @PostMapping("tableInfo")
@ -31,7 +31,7 @@ public class SqlParserController {
@Operation(summary = "解析SQL成列数据", description = "解析SQL成列数据") @Operation(summary = "解析SQL成列数据", description = "解析SQL成列数据")
@PostMapping("columnMetaData") @PostMapping("columnMetaData")
public Result<List<ColumnMetaData>> columnMetaData(String sql) { public Result<List<ColumnMetaData>> columnMetaData(String sql) {
List<ColumnMetaData> vo = sqlParserService.tableColumnInfo(sql); List<ColumnMetaData> vo = sqlParserService.getColumnInfoList(sql);
return Result.success(vo); return Result.success(vo);
} }
} }

View File

@ -1,6 +1,6 @@
package cn.bunny.controller; package cn.bunny.controller;
import cn.bunny.core.factory.ConcreteDatabaseInfoService; import cn.bunny.core.factory.DatabaseMetadataProvider;
import cn.bunny.domain.entity.ColumnMetaData; import cn.bunny.domain.entity.ColumnMetaData;
import cn.bunny.domain.entity.DatabaseInfoMetaData; import cn.bunny.domain.entity.DatabaseInfoMetaData;
import cn.bunny.domain.entity.TableMetaData; import cn.bunny.domain.entity.TableMetaData;
@ -22,7 +22,7 @@ import java.util.List;
public class TableController { public class TableController {
private final TableService tableService; private final TableService tableService;
private final ConcreteDatabaseInfoService concreteDatabaseInfoService; private final DatabaseMetadataProvider databaseMetadataProvider;
@Operation(summary = "当前数据库信息", description = "当前连接的数据库信息") @Operation(summary = "当前数据库信息", description = "当前连接的数据库信息")
@GetMapping("databaseInfoMetaData") @GetMapping("databaseInfoMetaData")
@ -34,21 +34,21 @@ public class TableController {
@Operation(summary = "数据库所有的表", description = "获取[当前/所有]数据库表") @Operation(summary = "数据库所有的表", description = "获取[当前/所有]数据库表")
@GetMapping("databaseTableList") @GetMapping("databaseTableList")
public Result<List<TableMetaData>> databaseTableList(String dbName) { public Result<List<TableMetaData>> databaseTableList(String dbName) {
List<TableMetaData> list = concreteDatabaseInfoService.databaseTableList(dbName); List<TableMetaData> list = databaseMetadataProvider.getTableMetadataBatch(dbName);
return Result.success(list); return Result.success(list);
} }
@Operation(summary = "表属性", description = "获取当前查询表属性") @Operation(summary = "表属性", description = "获取当前查询表属性")
@GetMapping("tableMetaData") @GetMapping("tableMetaData")
public Result<TableMetaData> tableMetaData(String tableName) { public Result<TableMetaData> tableMetaData(String tableName) {
TableMetaData tableMetaData = concreteDatabaseInfoService.getTableMetadata(tableName); TableMetaData tableMetaData = databaseMetadataProvider.getTableMetadata(tableName);
return Result.success(tableMetaData); return Result.success(tableMetaData);
} }
@Operation(summary = "表的列属性", description = "获取当前查询表中列属性") @Operation(summary = "表的列属性", description = "获取当前查询表中列属性")
@GetMapping("tableColumnInfo") @GetMapping("tableColumnInfo")
public Result<List<ColumnMetaData>> tableColumnInfo(String tableName) { public Result<List<ColumnMetaData>> tableColumnInfo(String tableName) {
List<ColumnMetaData> columnInfo = concreteDatabaseInfoService.tableColumnInfo(tableName); List<ColumnMetaData> columnInfo = databaseMetadataProvider.getColumnInfoList(tableName);
return Result.success(columnInfo); return Result.success(columnInfo);
} }
} }

View File

@ -1,70 +0,0 @@
package cn.bunny.core.factory;
import cn.bunny.domain.entity.ColumnMetaData;
import cn.bunny.domain.entity.TableMetaData;
import lombok.SneakyThrows;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.DatabaseMetaData;
import java.sql.ResultSet;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
@Component
public abstract class AbstractDatabaseInfo {
public DataSource dataSource;
@Autowired
public void setDataSource(DataSource dataSource) {
this.dataSource = dataSource;
}
/**
* 获取表的所有主键列名
*
* @param tableName 表名
* @return 主键列名的集合
*/
@SneakyThrows
public Set<String> findPrimaryKeyColumns(String tableName) {
// 主键的key
Set<String> primaryKeys = new HashSet<>();
try (Connection connection = dataSource.getConnection()) {
DatabaseMetaData metaData = connection.getMetaData();
// 当前表的主键
ResultSet pkResultSet = metaData.getPrimaryKeys(null, null, tableName);
while (pkResultSet.next()) {
// 列字段
String columnName = pkResultSet.getString("COLUMN_NAME").toLowerCase();
primaryKeys.add(columnName);
}
return primaryKeys;
}
}
/**
* 解析 sql 表信息
*
* @param name 表名称或sql
* @return 表西悉尼
*/
public abstract TableMetaData getTableMetadata(String name);
/**
* 获取当前表的列属性
*
* @param name 表名称或sql
* @return 当前表所有的列内容
*/
public abstract List<ColumnMetaData> tableColumnInfo(String name);
}

View File

@ -3,23 +3,57 @@ package cn.bunny.core.factory;
import cn.bunny.domain.entity.ColumnMetaData; import cn.bunny.domain.entity.ColumnMetaData;
import cn.bunny.domain.entity.DatabaseInfoMetaData; import cn.bunny.domain.entity.DatabaseInfoMetaData;
import cn.bunny.domain.entity.TableMetaData; import cn.bunny.domain.entity.TableMetaData;
import cn.bunny.exception.GeneratorCodeException;
import cn.bunny.utils.TypeConvertUtil; import cn.bunny.utils.TypeConvertUtil;
import lombok.RequiredArgsConstructor;
import lombok.SneakyThrows; import lombok.SneakyThrows;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Value; import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import javax.sql.DataSource;
import java.sql.Connection; import java.sql.Connection;
import java.sql.DatabaseMetaData; import java.sql.DatabaseMetaData;
import java.sql.ResultSet; import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.*; import java.util.*;
@Component @Component
public class ConcreteDatabaseInfoService extends AbstractDatabaseInfo { @RequiredArgsConstructor
public class DatabaseMetadataProvider implements IMetadataProvider {
private final DataSource dataSource;
@Value("${bunny.master.database}") @Value("${bunny.master.database}")
private String currentDatabase; private String currentDatabase;
/**
* 获取表的所有主键列名
*
* @param tableName 表名
* @return 主键列名的集合
*/
public Set<String> getPrimaryKeys(String tableName) {
// 主键的key
Set<String> primaryKeys = new HashSet<>();
try (Connection connection = dataSource.getConnection()) {
DatabaseMetaData metaData = connection.getMetaData();
// 当前表的主键
ResultSet pkResultSet = metaData.getPrimaryKeys(null, null, tableName);
while (pkResultSet.next()) {
// 列字段
String columnName = pkResultSet.getString("COLUMN_NAME").toLowerCase();
primaryKeys.add(columnName);
}
return primaryKeys;
} catch (SQLException e) {
throw new GeneratorCodeException("获取主键失败:" + e.getMessage());
}
}
/** /**
* 数据库所有的信息 * 数据库所有的信息
* *
@ -45,17 +79,17 @@ public class ConcreteDatabaseInfoService extends AbstractDatabaseInfo {
/** /**
* 解析 sql 表信息 * 解析 sql 表信息
* *
* @param tableName 表名称或sql * @param identifier 表名称或sql
* @return 表西悉尼 * @return 表西悉尼
*/ */
@SneakyThrows @SneakyThrows
@Override @Override
public TableMetaData getTableMetadata(String tableName) { public TableMetaData getTableMetadata(String identifier) {
TableMetaData tableMetaData; TableMetaData tableMetaData;
try (Connection connection = dataSource.getConnection()) { try (Connection connection = dataSource.getConnection()) {
DatabaseMetaData metaData = connection.getMetaData(); DatabaseMetaData metaData = connection.getMetaData();
ResultSet tables = metaData.getTables(null, null, tableName, new String[]{"TABLE"}); ResultSet tables = metaData.getTables(null, null, identifier, new String[]{"TABLE"});
// 获取表的注释信息 // 获取表的注释信息
if (tables.next()) { if (tables.next()) {
@ -69,7 +103,7 @@ public class ConcreteDatabaseInfoService extends AbstractDatabaseInfo {
String tableType = tables.getString("TABLE_TYPE"); String tableType = tables.getString("TABLE_TYPE");
tableMetaData = TableMetaData.builder() tableMetaData = TableMetaData.builder()
.tableName(tableName) .tableName(identifier)
.comment(remarks) .comment(remarks)
.tableCat(tableCat) .tableCat(tableCat)
.tableType(tableType) .tableType(tableType)
@ -88,12 +122,12 @@ public class ConcreteDatabaseInfoService extends AbstractDatabaseInfo {
* @return 所有表信息 * @return 所有表信息
*/ */
@SneakyThrows @SneakyThrows
public List<TableMetaData> databaseTableList(String dbName) { public List<TableMetaData> getTableMetadataBatch(String dbName) {
// 当前数据库数据库所有的表 // 当前数据库数据库所有的表
List<TableMetaData> allTableInfo = new ArrayList<>(); List<TableMetaData> allTableInfo = new ArrayList<>();
try (Connection connection = dataSource.getConnection()) { try (Connection conn = dataSource.getConnection()) {
DatabaseMetaData metaData = connection.getMetaData(); DatabaseMetaData metaData = conn.getMetaData();
// 当前数据库中所有的表 // 当前数据库中所有的表
ResultSet tables = metaData.getTables(dbName, null, "%", new String[]{"TABLE"}); ResultSet tables = metaData.getTables(dbName, null, "%", new String[]{"TABLE"});
@ -115,20 +149,20 @@ public class ConcreteDatabaseInfoService extends AbstractDatabaseInfo {
/** /**
* 获取当前表的列属性 * 获取当前表的列属性
* *
* @param tableName 表名称或sql * @param identifier 表名称或sql
* @return 当前表所有的列内容 * @return 当前表所有的列内容
*/ */
@SneakyThrows @SneakyThrows
@Override @Override
public List<ColumnMetaData> tableColumnInfo(String tableName) { public List<ColumnMetaData> getColumnInfoList(String identifier) {
try (Connection connection = dataSource.getConnection()) { try (Connection connection = dataSource.getConnection()) {
DatabaseMetaData metaData = connection.getMetaData(); DatabaseMetaData metaData = connection.getMetaData();
Map<String, ColumnMetaData> map = new LinkedHashMap<>(); Map<String, ColumnMetaData> map = new LinkedHashMap<>();
// 当前表的主键 // 当前表的主键
Set<String> primaryKeyColumns = findPrimaryKeyColumns(tableName); Set<String> primaryKeyColumns = getPrimaryKeys(identifier);
// 当前表的列信息 // 当前表的列信息
try (ResultSet columnsRs = metaData.getColumns(null, null, tableName, null)) { try (ResultSet columnsRs = metaData.getColumns(null, null, identifier, null)) {
while (columnsRs.next()) { while (columnsRs.next()) {
ColumnMetaData column = new ColumnMetaData(); ColumnMetaData column = new ColumnMetaData();
// 列字段 // 列字段

View File

@ -0,0 +1,26 @@
package cn.bunny.core.factory;
import cn.bunny.domain.entity.ColumnMetaData;
import cn.bunny.domain.entity.TableMetaData;
import java.util.List;
public interface IMetadataProvider {
/**
* 解析 sql 表信息
*
* @param identifier 表名称或sql
* @return 表西悉尼
*/
TableMetaData getTableMetadata(String identifier);
/**
* 获取当前表的列属性
*
* @param identifier 表名称或sql
* @return 当前表所有的列内容
*/
List<ColumnMetaData> getColumnInfoList(String identifier);
}

View File

@ -16,24 +16,24 @@ import java.util.regex.Matcher;
import java.util.regex.Pattern; import java.util.regex.Pattern;
@Component @Component
public class ConcreteSqlParserDatabaseInfoService extends AbstractDatabaseInfo { public class SqlMetadataProvider implements IMetadataProvider {
/** /**
* 解析 sql 表信息 * 解析 sql 表信息
* 先解析SQL语句解析列字段信息 * 先解析SQL语句解析列字段信息
* *
* @param sql 表名称或sql * @param identifier 表名称或sql
* @return 表西悉尼 * @return 表西悉尼
* @see CCJSqlParserUtil 使用这个工具进行SQL的解析 * @see CCJSqlParserUtil 使用这个工具进行SQL的解析
*/ */
@Override @Override
public TableMetaData getTableMetadata(String sql) { public TableMetaData getTableMetadata(String identifier) {
TableMetaData tableInfo = new TableMetaData(); TableMetaData tableInfo = new TableMetaData();
// 解析sql // 解析sql
Statement statement; Statement statement;
try { try {
statement = CCJSqlParserUtil.parse(sql); statement = CCJSqlParserUtil.parse(identifier);
} catch (JSQLParserException e) { } catch (JSQLParserException e) {
throw new GeneratorCodeException("SQL解析失败"); throw new GeneratorCodeException("SQL解析失败");
} }
@ -61,15 +61,15 @@ public class ConcreteSqlParserDatabaseInfoService extends AbstractDatabaseInfo {
/** /**
* 获取当前表的列属性 * 获取当前表的列属性
* *
* @param sql 表名称或sql * @param identifier 表名称或sql
* @return 当前表所有的列内容 * @return 当前表所有的列内容
*/ */
@Override @Override
public List<ColumnMetaData> tableColumnInfo(String sql) { public List<ColumnMetaData> getColumnInfoList(String identifier) {
// 解析sql // 解析sql
Statement statement; Statement statement;
try { try {
statement = CCJSqlParserUtil.parse(sql); statement = CCJSqlParserUtil.parse(identifier);
} catch (JSQLParserException e) { } catch (JSQLParserException e) {
throw new RuntimeException("SQL解析失败"); throw new RuntimeException("SQL解析失败");
} }

View File

@ -15,7 +15,7 @@ import java.util.Date;
* 使用模板方法方便扩展 * 使用模板方法方便扩展
* 如果需要继承 AbstractVmsGenerator * 如果需要继承 AbstractVmsGenerator
*/ */
public class VmsArgumentDtoBaseVmsGeneratorTemplate extends AbstractVmsGeneratorTemplate { public class VmsArgumentDtoBaseTemplateGenerator extends AbstractTemplateGenerator {
private final VmsArgumentDto dto; private final VmsArgumentDto dto;
private final String path; private final String path;
@ -26,7 +26,7 @@ public class VmsArgumentDtoBaseVmsGeneratorTemplate extends AbstractVmsGenerator
* @param path 当前路径 * @param path 当前路径
* @param tableMetaData 表名称 * @param tableMetaData 表名称
*/ */
public VmsArgumentDtoBaseVmsGeneratorTemplate(VmsArgumentDto dto, String path, TableMetaData tableMetaData) { public VmsArgumentDtoBaseTemplateGenerator(VmsArgumentDto dto, String path, TableMetaData tableMetaData) {
this.dto = dto; this.dto = dto;
this.path = path; this.path = path;
this.tableMetaData = tableMetaData; this.tableMetaData = tableMetaData;

View File

@ -1,6 +1,6 @@
package cn.bunny.service.impl; package cn.bunny.service.impl;
import cn.bunny.core.factory.ConcreteDatabaseInfoService; import cn.bunny.core.factory.DatabaseMetadataProvider;
import cn.bunny.domain.entity.DatabaseInfoMetaData; import cn.bunny.domain.entity.DatabaseInfoMetaData;
import cn.bunny.domain.entity.TableMetaData; import cn.bunny.domain.entity.TableMetaData;
import cn.bunny.service.TableService; import cn.bunny.service.TableService;
@ -15,7 +15,7 @@ import java.util.stream.Collectors;
@RequiredArgsConstructor @RequiredArgsConstructor
public class TableServiceImpl implements TableService { public class TableServiceImpl implements TableService {
private final ConcreteDatabaseInfoService concreteDatabaseInfoService; private final DatabaseMetadataProvider databaseMetadataProvider;
/** /**
* 数据库所有的信息 * 数据库所有的信息
@ -25,7 +25,7 @@ public class TableServiceImpl implements TableService {
@SneakyThrows @SneakyThrows
@Override @Override
public DatabaseInfoMetaData databaseInfoMetaData() { public DatabaseInfoMetaData databaseInfoMetaData() {
List<TableMetaData> databaseTableList = concreteDatabaseInfoService.databaseTableList(null); List<TableMetaData> databaseTableList = databaseMetadataProvider.getTableMetadataBatch(null);
// 将当前数据库表分组以数据库名称为key // 将当前数据库表分组以数据库名称为key
List<TableMetaData> databaseList = databaseTableList.stream() List<TableMetaData> databaseList = databaseTableList.stream()
@ -37,7 +37,7 @@ public class TableServiceImpl implements TableService {
return tableInfoVo; return tableInfoVo;
}).toList(); }).toList();
DatabaseInfoMetaData databaseInfoMetaData = concreteDatabaseInfoService.databaseInfoMetaData(); DatabaseInfoMetaData databaseInfoMetaData = databaseMetadataProvider.databaseInfoMetaData();
databaseInfoMetaData.setDatabaseList(databaseList); databaseInfoMetaData.setDatabaseList(databaseList);
return databaseInfoMetaData; return databaseInfoMetaData;

View File

@ -1,8 +1,8 @@
package cn.bunny.service.impl.vms; package cn.bunny.service.impl.vms;
import cn.bunny.core.factory.ConcreteDatabaseInfoService; import cn.bunny.core.factory.DatabaseMetadataProvider;
import cn.bunny.core.factory.ConcreteSqlParserDatabaseInfoService; import cn.bunny.core.factory.SqlMetadataProvider;
import cn.bunny.core.template.VmsArgumentDtoBaseVmsGeneratorTemplate; import cn.bunny.core.template.VmsArgumentDtoBaseTemplateGenerator;
import cn.bunny.domain.dto.VmsArgumentDto; import cn.bunny.domain.dto.VmsArgumentDto;
import cn.bunny.domain.entity.ColumnMetaData; import cn.bunny.domain.entity.ColumnMetaData;
import cn.bunny.domain.entity.TableMetaData; import cn.bunny.domain.entity.TableMetaData;
@ -25,8 +25,8 @@ import java.util.stream.Collectors;
@RequiredArgsConstructor @RequiredArgsConstructor
public class VmsCodeGeneratorService { public class VmsCodeGeneratorService {
private final ConcreteDatabaseInfoService databaseInfoCore; private final DatabaseMetadataProvider databaseInfoCore;
private final ConcreteSqlParserDatabaseInfoService sqlParserDatabaseInfo; private final SqlMetadataProvider sqlParserDatabaseInfo;
/** /**
* 根据DTO生成代码模板 * 根据DTO生成代码模板
@ -44,7 +44,7 @@ public class VmsCodeGeneratorService {
return dto.getPath().stream() return dto.getPath().stream()
.map(path -> { .map(path -> {
VmsArgumentDtoBaseVmsGeneratorTemplate generator = new VmsArgumentDtoBaseVmsGeneratorTemplate(dto, path, tableMetaData); VmsArgumentDtoBaseTemplateGenerator generator = new VmsArgumentDtoBaseTemplateGenerator(dto, path, tableMetaData);
StringWriter writer = generator.generatorCodeTemplate(tableMetaData, columnInfoList); StringWriter writer = generator.generatorCodeTemplate(tableMetaData, columnInfoList);
String processedPath = VmsUtil.handleVmFilename(path, tableMetaData.getTableName()); String processedPath = VmsUtil.handleVmFilename(path, tableMetaData.getTableName());
@ -84,8 +84,8 @@ public class VmsCodeGeneratorService {
*/ */
private List<ColumnMetaData> getColumnInfoList(String sql, String tableName) { private List<ColumnMetaData> getColumnInfoList(String sql, String tableName) {
return StringUtils.hasText(sql) return StringUtils.hasText(sql)
? sqlParserDatabaseInfo.tableColumnInfo(sql) ? sqlParserDatabaseInfo.getColumnInfoList(sql)
: databaseInfoCore.tableColumnInfo(tableName).stream().distinct().toList(); : databaseInfoCore.getColumnInfoList(tableName).stream().distinct().toList();
} }
} }

View File

@ -14,7 +14,7 @@ import java.util.ArrayList;
import java.util.List; import java.util.List;
@SpringBootTest @SpringBootTest
class ConcreteDatabaseInfoServiceCoreTest { class DatabaseMetadataProviderCoreTest {
String tableName = "sys_i18n"; String tableName = "sys_i18n";