在之前,我写过一篇【设计】设计一个web版的数据库管理平台后端精要 的文章,文章讲了一个web版数据库管理平台的实现思路及主要代码。
最近,我看了下Mybatis的源码,觉得Mybatis的分层架构挺好,所以想到了完善下web版数据库管理平台中,关于sql查询的功能。
在上期文章中,关于sql的执行,代码是最简单的
// 执行SQL
jdbcTemplate.execute(sql);
对于sql查询功能来说,这是远远不够的,sql查询需要查询出数据库中的结果,并显示在网页上。这里我们比Mybatis简单,我们不需要实现结果与java类型的映射,只是显示出来就好。
网上有个图片(原图地址,如有侵权,请联系我),很好的反应了我即将要做的事情
方案
也就是说,我要将原来直接执行sql的方式进行解耦,改为调用SQL执行器去执行。
参考Mybatis,我们添加了
SqlSession
│
├── Configuration (配置中心)
│
└── Executor (执行器)
│
├── StatementHandler (语句处理器)
│
└── ResultSetHandler (结果集处理器)
以下是本次完善的类图。
类图说明:
- 核心类关系:
- SqlSession 是入口类,包含Configuration和Executor
- Executor 接口定义了执行SQL的核心方法
- SimpleExecutor 是基础实现,使用StatementHandler执行SQL
- 执行流程相关类:
- StatementHandler 负责SQL语句准备和执行
- SimpleStatementHandler 是基础实现,使用PreparedStatement
- ResultSetHandler 负责结果集处理
- MapResultSetHandler 将ResultSet转为List
- 配置类:
- Configuration 持有数据源等配置信息
- 依赖关系:
- 实线箭头表示组合关系(强拥有)
- 虚线箭头表示依赖关系(临时使用)
- 空心三角箭头表示接口实现
详细设计
Configuration 配置类
public class Configuration {
private DataSource dataSource;
private boolean cacheEnabled = false;
// 其他配置项...
public Configuration(DataSource dataSource) {
this.dataSource = dataSource;
}
// getters and setters...
}
SqlSession 实现
public class SqlSession {
private final Configuration configuration;
private final Executor executor;
public SqlSession(Configuration configuration) {
this.configuration = configuration;
this.executor = new SimpleExecutor(configuration);
}
public List<Map<String, Object>> selectList(String sql, Object... parameters) {
return executor.query(sql, parameters);
}
public void close() {
executor.close();
}
}
Executor 执行器
public interface Executor {
List<Map<String, Object>> query(String sql, Object... parameters);
void close();
}
public class SimpleExecutor implements Executor {
private final Configuration configuration;
private Connection connection;
public SimpleExecutor(Configuration configuration) {
this.configuration = configuration;
}
@Override
public List<Map<String, Object>> query(String sql, Object... parameters) {
try {
StatementHandler statementHandler = new SimpleStatementHandler(configuration);
return statementHandler.query(sql, parameters);
} catch (SQLException e) {
throw new RuntimeException("Error executing query: " + sql, e);
}
}
@Override
public void close() {
if (connection != null) {
try {
connection.close();
} catch (SQLException e) {
// ignore
}
}
}
}
StatementHandler 语句处理器
public interface StatementHandler {
List<Map<String, Object>> query(String sql, Object... parameters) throws SQLException;
}
public class SimpleStatementHandler implements StatementHandler {
private final Configuration configuration;
private final ResultSetHandler resultSetHandler;
public SimpleStatementHandler(Configuration configuration) {
this.configuration = configuration;
this.resultSetHandler = new MapResultSetHandler();
}
@Override
public List<Map<String, Object>> query(String sql, Object... parameters) throws SQLException {
Connection connection = null;
PreparedStatement stmt = null;
ResultSet rs = null;
try {
connection = configuration.getDataSource().getConnection();
stmt = connection.prepareStatement(sql);
// 设置参数
for (int i = 0; i < parameters.length; i++) {
stmt.setObject(i + 1, parameters[i]);
}
rs = stmt.executeQuery();
return resultSetHandler.handleResultSets(rs);
} finally {
if (rs != null) {
try {
rs.close();
} catch (SQLException e) {
// ignore
}
}
if (stmt != null) {
try {
stmt.close();
} catch (SQLException e) {
// ignore
}
}
if (connection != null) {
try {
connection.close();
} catch (SQLException e) {
// ignore
}
}
}
}
}
ResultSetHandler 结果集处理器
public interface ResultSetHandler {
List<Map<String, Object>> handleResultSets(ResultSet rs) throws SQLException;
}
public class MapResultSetHandler implements ResultSetHandler {
@Override
public List<Map<String, Object>> handleResultSets(ResultSet rs) throws SQLException {
List<Map<String, Object>> resultList = new ArrayList<>();
ResultSetMetaData metaData = rs.getMetaData();
int columnCount = metaData.getColumnCount();
while (rs.next()) {
Map<String, Object> row = new LinkedHashMap<>();
for (int i = 1; i <= columnCount; i++) {
String columnName = metaData.getColumnLabel(i);
if (columnName == null || columnName.isEmpty()) {
columnName = metaData.getColumnName(i);
}
row.put(columnName, rs.getObject(i));
}
resultList.add(row);
}
return resultList;
}
}
使用示例
// 初始化配置
DataSource dataSource = ... // 创建数据源
Configuration configuration = new Configuration(dataSource);
// 创建SqlSession
try (SqlSession sqlSession = new SqlSession(configuration)) {
// 执行查询
List<Map<String, Object>> result = sqlSession.selectList(
"SELECT * FROM users WHERE age > ?",
18
);
// 处理结果
for (Map<String, Object> row : result) {
System.out.println(row);
}
}