首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 相關知識

自研輕量級 DbUnit:基於 HSQLDB 內存庫與自引用表遞歸清理的測試數據隔離方案

     編輯:Java 相關知識

背景痛點

數據庫測試需保證每個測試方法獨立、數據庫狀態穩定。DbUnit 雖能通過固定數據集實現,但無法處理非空外鍵約束下的刪除順序問題,尤其自引用表(如組織表的上級組織外鍵指向自身)會導致刪除失敗或級聯刪除誤傷數據。

自研方案:SqlRunner

摒棄 Hibernate,直接用 JDBC SQL,保持測試基礎設施獨立穩定。

核心類

public class SqlRunner {
    static { Class.forName(\"org.hsqldb.jdbcDriver\"); }

    public static void executeUpdate(String sql) { /* JDBC 執行 update */ }

    /** 判斷表是否存在被引用記錄(自引用場景) */
    public static boolean isUndeletableForSelfReference(String table, String fkColumn) {
        // 查詢 count(*) WHERE fkColumn IS NOT NULL
        // 有記錄引用其他記錄 → true(不能直接刪表)
    }
}

測試夾具

@Before
public void setUp() {
    SqlRunner.executeUpdate(\"INSERT INTO 組織分類 VALUES(1, '教育系統')\");
    SqlRunner.executeUpdate(\"INSERT INTO 組織分類 VALUES(2, '商貿系統')\");
    SqlRunner.executeUpdate(\"INSERT INTO 組織 VALUES(1, '中國貿易部', '北京', 2, NULL)\");
    SqlRunner.executeUpdate(\"INSERT INTO 組織 VALUES(2, '北京貿易廳', '北京', 2, 1)\");
    SqlRunner.executeUpdate(\"INSERT INTO 組織 VALUES(5, '北京昌平貿易局', '北京', 2, 2)\");
    // 5→2→1 鏈式自引用
    SqlRunner.executeUpdate(\"INSERT INTO 部門 VALUES(1, '財務科', 2)\");
}

@After
public void tearDown() {
    SqlRunner.executeUpdate(\"DELETE FROM 部門\");  // 先刪被引用表

    // 遞歸刪除自引用表:先刪葉子節點(無人引用的記錄)
    while (SqlRunner.isUndeletableForSelfReference(\"組織\", \"上級組織編號\")) {
        SqlRunner.executeUpdate(
            \"DELETE FROM 組織 WHERE 上級組織編號 IS NOT NULL \" +
            \"AND 編號 NOT IN (SELECT 上級組織編號 FROM 組織 WHERE 上級組織編號 IS NOT NULL)\"
        );
    }
    SqlRunner.executeUpdate(\"DELETE FROM 組織\");
    SqlRunner.executeUpdate(\"DELETE FROM 組織分類\");
}

關鍵邏輯解析

while 循環語義:只要存在「被引用的記錄」(即有其他記錄的外鍵指向它),就先刪除「引用了其他記錄但自己不被引用的葉子節點」。循環結束後,表中無任何被引用記錄,安全執行全表刪除。

技術選型理由

  • HSQLDB 內存模式:jdbc:hsqldb:mem:testingdb,毫秒級啟動,測試隔離天然滿足,無需清理磁盤。
  • JDBC 而非 Hibernate:測試基礎設施不可依賴待測代碼(Hibernate 映射),避免重構連鎖修改。
  • 速度優先:28 個測試方法、近千行代碼,全量運行 <8 秒,瓶頸在 setUp/tearDown 重複執行,可通過精簡基礎數據權衡。

適用場景與擴展

  • 單元/集成測試數據庫層隔離。
  • 複雜外鍵拓撲(自引用、菱形引用、多層級聯)。
  • 可擴展為通用 TestDataManager:XML/JSON 定義數據集、拓撲排序自動生成刪除順序。

自研 DbUnit 不足百行代碼,卻精準解決了傳統工具在複雜約束下的無力感,是測試基礎設施「小而美」的典範。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved