1. 引言
在第二篇中,我们设计了系统的整体架构,明确了JDBC驱动作为客户端入口的角色。本篇将深入探讨JDBC驱动的实现细节,确保其符合SQL ANSI 92标准,支持事务、JSON操作和高性能目标。通过与SQL解析器和内核的集成,展示从SQL输入到结果返回的完整流程。
2. JDBC驱动的目标与功能
2.1 目标
- 提供标准的JDBC接口,兼容现有Java数据库工具和框架。
- 支持轻量化设计,无外部依赖。
- 集成日志管理器,记录SQL执行和事务操作。
- 确保高效的SQL执行和事务管理。
2.2 功能
- 连接管理:通过JDBC URL建立与数据库的连接。
- SQL执行:支持DDL、DML和事务语句。
- 结果处理:返回查询结果集,支持JSON数据类型。
- 日志记录:记录关键操作到WAL和调试日志。
- 配置支持:允许切换内存/文件模式。
3. JDBC驱动的核心接口实现
JDBC驱动需要实现java.sql
包中的关键接口,以下是主要实现:
3.1 Driver 接口
- 作用:注册驱动并处理连接请求。
- 实现:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
import java.sql.Driver; import java.sql.DriverManager; import java.sql.SQLException; public class LightweightDriver implements Driver { static { try { DriverManager.registerDriver(new LightweightDriver()); } catch (SQLException e) { throw new RuntimeException("Failed to register LightweightDriver", e); } } @Override public Connection connect(String url, java.util.Properties info) throws SQLException { if (!acceptsURL(url)) return null; return new LightweightConnection(url, info); } @Override public boolean acceptsURL(String url) throws SQLException { return url.startsWith("jdbc:lightweight:"); } @Override public int getMajorVersion() { return 1; } @Override public int getMinorVersion() { return 0; } // 其他方法省略 }
3.2 Connection 接口
- 作用:管理数据库连接和事务。
- 实现:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50
import java.sql.Connection; import java.sql.Statement; import java.sql.SQLException; public class LightweightConnection implements Connection { private final String url; private final LightweightDatabase db; private boolean autoCommit = true; public LightweightConnection(String url, java.util.Properties info) { this.url = url; this.db = new LightweightDatabase(url); // 初始化数据库实例 db.getLogger().info("Connection established: " + url); // 日志记录 } @Override public Statement createStatement() throws SQLException { return new LightweightStatement(this, db); } @Override public void setAutoCommit(boolean autoCommit) throws SQLException { this.autoCommit = autoCommit; if (!autoCommit) { db.beginTransaction(); db.getLogger().info("Transaction begun"); } } @Override public void commit() throws SQLException { db.commitTransaction(); db.getLogger().info("Transaction committed"); if (!autoCommit) db.beginTransaction(); } @Override public void rollback() throws SQLException { db.rollbackTransaction(); db.getLogger().info("Transaction rolled back"); if (!autoCommit) db.beginTransaction(); } @Override public void close() throws SQLException { db.close(); db.getLogger().info("Connection closed"); } // 其他方法省略 }
3.3 Statement 接口
- 作用:执行SQL语句并返回结果。
- 实现:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41
import java.sql.Statement; import java.sql.ResultSet; import java.sql.SQLException; public class LightweightStatement implements Statement { private final LightweightConnection conn; private final LightweightDatabase db; public LightweightStatement(LightweightConnection conn, LightweightDatabase db) { this.conn = conn; this.db = db; } @Override public ResultSet executeQuery(String sql) throws SQLException { db.getLogger().info("Executing query: " + sql); Object result = db.execute(sql); // 调用数据库内核 if (result instanceof List) { db.getLogger().debug("Query returned " + ((List<?>) result).size() + " rows"); return new LightweightResultSet((List<Map<String, Object>>) result); } throw new SQLException("Not a query statement"); } @Override public int executeUpdate(String sql) throws SQLException { db.getLogger().info("Executing update: " + sql); Object result = db.execute(sql); if (result instanceof Integer) { db.getLogger().debug("Update affected " + result + " rows"); return (int) result; } throw new SQLException("Not an update statement"); } @Override public void close() throws SQLException { // 清理资源 } // 其他方法省略 }
3.4 ResultSet 接口
- 作用:处理查询结果,支持JSON数据访问。
- 实现:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38
import java.sql.ResultSet; import java.sql.SQLException; import java.util.Iterator; import java.util.List; import java.util.Map; public class LightweightResultSet implements ResultSet { private final List<Map<String, Object>> rows; private Iterator<Map<String, Object>> iterator; private Map<String, Object> currentRow; public LightweightResultSet(List<Map<String, Object>> rows) { this.rows = rows; this.iterator = rows.iterator(); } @Override public boolean next() throws SQLException { if (iterator.hasNext()) { currentRow = iterator.next(); return true; } return false; } @Override public String getString(int columnIndex) throws SQLException { String key = currentRow.keySet().toArray(new String[0])[columnIndex - 1]; return String.valueOf(currentRow.get(key)); } @Override public void close() throws SQLException { iterator = null; currentRow = null; } // 其他方法省略(如getInt、getObject等) }
4. 与SQL解析器的集成
JDBC驱动通过LightweightDatabase
类与SQL解析器交互:
- LightweightDatabase:数据库内核的入口。
- 实现:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
public class LightweightDatabase { private final SQLParser parser; private final StorageEngine storage; private final TransactionManager txManager; private final LoggingManager logger; public LightweightDatabase(String url) { this.parser = new SQLParser(); // 使用ANTLR初始化 this.storage = new StorageEngine(); this.txManager = new TransactionManager(); this.logger = new LoggingManager(url); // 初始化日志管理器 } public Object execute(String sql) { Statement ast = parser.parse(sql); // 解析SQL if (ast instanceof SelectStatement) { return storage.executeSelect((SelectStatement) ast, txManager.getCurrentTxId()); } else if (ast instanceof InsertStatement) { logger.logWAL("INSERT: " + sql); // 记录WAL日志 return storage.executeInsert((InsertStatement) ast, txManager.getCurrentTxId()); } // 其他语句处理 return null; } public void beginTransaction() { txManager.begin(); } public void commitTransaction() { txManager.commit(); } public void rollbackTransaction() { txManager.rollback(); } public void close() { /* 清理资源 */ } public LoggingManager getLogger() { return logger; } }
日志管理器(Logging Manager)示例
- 简单实现:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
public class LoggingManager { private final String logFile; public LoggingManager(String url) { this.logFile = url.replace("jdbc:lightweight:", "") + ".log"; } public void info(String message) { System.out.println("[INFO] " + message); // 实际可写入文件 } public void debug(String message) { System.out.println("[DEBUG] " + message); } public void logWAL(String operation) { System.out.println("[WAL] " + operation); // 实际写入WAL文件 } }
5. 执行流程图
以下是JDBC驱动的SQL执行流程:
sequenceDiagram
participant C as 客户端
participant D as JDBC驱动
participant P as SQL解析器
participant S as 存储引擎
participant T as 事务管理器
participant L as 日志管理器
C->>D: executeQuery("SELECT * FROM users")
D->>L: info("Executing query: ...")
D->>P: parse("SELECT * FROM users")
P-->>D: AST
D->>T: getCurrentTxId()
T-->>D: txId
D->>S: executeSelect(AST, txId)
S-->>D: List<Map>
D->>L: debug("Query returned X rows")
D-->>C: ResultSet
- 流程说明:
- 客户端调用
Statement.executeQuery
。 - JDBC驱动将SQL传递给解析器,生成AST。
- 获取当前事务ID,确保MVCC一致性。
- 调用存储引擎执行查询,返回结果。
- 客户端调用
6. 测试示例
|
|
7. 下一步展望
下一篇文章将聚焦“存储引擎实现”,详细设计内存和文件存储机制,支持B+树索引和JSON数据类型,并与MVCC事务集成。
总结
第三篇实现了JDBC驱动的核心接口,完成了从客户端SQL请求到数据库内核的桥接。通过与SQL解析器的集成,展示了端到端的执行流程。Mermaid图清晰呈现了交互过程,为后续存储引擎和事务管理奠定了基础。