基于Java的高性能轻量化数据库设计与实现 第三篇:JDBC驱动实现

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
  • 流程说明
    1. 客户端调用Statement.executeQuery
    2. JDBC驱动将SQL传递给解析器,生成AST。
    3. 获取当前事务ID,确保MVCC一致性。
    4. 调用存储引擎执行查询,返回结果。
6. 测试示例
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
Class.forName("com.yinlongfei.lightweight.database.jdbc.LightweightDriver");
Connection conn = DriverManager.getConnection("jdbc:lightweight:memory");
Statement stmt = conn.createStatement();
stmt.execute("CREATE TABLE users (id INT, data JSON)");
stmt.execute("INSERT INTO users VALUES (1, '{\"name\": \"Alice\"}')");
ResultSet rs = stmt.executeQuery("SELECT JSON_EXTRACT(data, '$.name') FROM users");
while (rs.next()) {
    System.out.println(rs.getString(1)); // 输出 "Alice"
}
conn.close();
7. 下一步展望

下一篇文章将聚焦“存储引擎实现”,详细设计内存和文件存储机制,支持B+树索引和JSON数据类型,并与MVCC事务集成。


总结

第三篇实现了JDBC驱动的核心接口,完成了从客户端SQL请求到数据库内核的桥接。通过与SQL解析器的集成,展示了端到端的执行流程。Mermaid图清晰呈现了交互过程,为后续存储引擎和事务管理奠定了基础。

updatedupdated2025-03-312025-03-31