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

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

View File

@ -1,6 +1,6 @@
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.DatabaseInfoMetaData;
import cn.bunny.domain.entity.TableMetaData;
@ -22,7 +22,7 @@ import java.util.List;
public class TableController {
private final TableService tableService;
private final ConcreteDatabaseInfoService concreteDatabaseInfoService;
private final DatabaseMetadataProvider databaseMetadataProvider;
@Operation(summary = "当前数据库信息", description = "当前连接的数据库信息")
@GetMapping("databaseInfoMetaData")
@ -34,21 +34,21 @@ public class TableController {
@Operation(summary = "数据库所有的表", description = "获取[当前/所有]数据库表")
@GetMapping("databaseTableList")
public Result<List<TableMetaData>> databaseTableList(String dbName) {
List<TableMetaData> list = concreteDatabaseInfoService.databaseTableList(dbName);
List<TableMetaData> list = databaseMetadataProvider.getTableMetadataBatch(dbName);
return Result.success(list);
}
@Operation(summary = "表属性", description = "获取当前查询表属性")
@GetMapping("tableMetaData")
public Result<TableMetaData> tableMetaData(String tableName) {
TableMetaData tableMetaData = concreteDatabaseInfoService.getTableMetadata(tableName);
TableMetaData tableMetaData = databaseMetadataProvider.getTableMetadata(tableName);
return Result.success(tableMetaData);
}
@Operation(summary = "表的列属性", description = "获取当前查询表中列属性")
@GetMapping("tableColumnInfo")
public Result<List<ColumnMetaData>> tableColumnInfo(String tableName) {
List<ColumnMetaData> columnInfo = concreteDatabaseInfoService.tableColumnInfo(tableName);
List<ColumnMetaData> columnInfo = databaseMetadataProvider.getColumnInfoList(tableName);
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.DatabaseInfoMetaData;
import cn.bunny.domain.entity.TableMetaData;
import cn.bunny.exception.GeneratorCodeException;
import cn.bunny.utils.TypeConvertUtil;
import lombok.RequiredArgsConstructor;
import lombok.SneakyThrows;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.DatabaseMetaData;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.*;
@Component
public class ConcreteDatabaseInfoService extends AbstractDatabaseInfo {
@RequiredArgsConstructor
public class DatabaseMetadataProvider implements IMetadataProvider {
private final DataSource dataSource;
@Value("${bunny.master.database}")
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 表信息
*
* @param tableName 表名称或sql
* @param identifier 表名称或sql
* @return 表西悉尼
*/
@SneakyThrows
@Override
public TableMetaData getTableMetadata(String tableName) {
public TableMetaData getTableMetadata(String identifier) {
TableMetaData tableMetaData;
try (Connection connection = dataSource.getConnection()) {
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()) {
@ -69,7 +103,7 @@ public class ConcreteDatabaseInfoService extends AbstractDatabaseInfo {
String tableType = tables.getString("TABLE_TYPE");
tableMetaData = TableMetaData.builder()
.tableName(tableName)
.tableName(identifier)
.comment(remarks)
.tableCat(tableCat)
.tableType(tableType)
@ -88,12 +122,12 @@ public class ConcreteDatabaseInfoService extends AbstractDatabaseInfo {
* @return 所有表信息
*/
@SneakyThrows
public List<TableMetaData> databaseTableList(String dbName) {
public List<TableMetaData> getTableMetadataBatch(String dbName) {
// 当前数据库数据库所有的表
List<TableMetaData> allTableInfo = new ArrayList<>();
try (Connection connection = dataSource.getConnection()) {
DatabaseMetaData metaData = connection.getMetaData();
try (Connection conn = dataSource.getConnection()) {
DatabaseMetaData metaData = conn.getMetaData();
// 当前数据库中所有的表
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 当前表所有的列内容
*/
@SneakyThrows
@Override
public List<ColumnMetaData> tableColumnInfo(String tableName) {
public List<ColumnMetaData> getColumnInfoList(String identifier) {
try (Connection connection = dataSource.getConnection()) {
DatabaseMetaData metaData = connection.getMetaData();
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()) {
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;
@Component
public class ConcreteSqlParserDatabaseInfoService extends AbstractDatabaseInfo {
public class SqlMetadataProvider implements IMetadataProvider {
/**
* 解析 sql 表信息
* 先解析SQL语句解析列字段信息
*
* @param sql 表名称或sql
* @param identifier 表名称或sql
* @return 表西悉尼
* @see CCJSqlParserUtil 使用这个工具进行SQL的解析
*/
@Override
public TableMetaData getTableMetadata(String sql) {
public TableMetaData getTableMetadata(String identifier) {
TableMetaData tableInfo = new TableMetaData();
// 解析sql
Statement statement;
try {
statement = CCJSqlParserUtil.parse(sql);
statement = CCJSqlParserUtil.parse(identifier);
} catch (JSQLParserException e) {
throw new GeneratorCodeException("SQL解析失败");
}
@ -61,15 +61,15 @@ public class ConcreteSqlParserDatabaseInfoService extends AbstractDatabaseInfo {
/**
* 获取当前表的列属性
*
* @param sql 表名称或sql
* @param identifier 表名称或sql
* @return 当前表所有的列内容
*/
@Override
public List<ColumnMetaData> tableColumnInfo(String sql) {
public List<ColumnMetaData> getColumnInfoList(String identifier) {
// 解析sql
Statement statement;
try {
statement = CCJSqlParserUtil.parse(sql);
statement = CCJSqlParserUtil.parse(identifier);
} catch (JSQLParserException e) {
throw new RuntimeException("SQL解析失败");
}

View File

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

View File

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

View File

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

View File

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