表 A 和表 B 通過 ID_RECEIVEID 關聯。需從表 A 查詢表 B 的 ID_RECEIVEID_OLD,再用該值反查表 A,如此循環直到表 B 無 ID_RECEIVEID_OLD 為止。
利用 HQL/JPQL 進行左連接,一次性獲取關聯鏈數據:
FROM TableA a
LEFT JOIN a.tableB b
LEFT JOIN b.tableA a2
LEFT JOIN a2.tableB b2
... -- 根據最大遞歸深度決定連接層數
優點:數據庫層面完成關聯,減少網絡往返。
缺點:遞歸深度不固定時難以構建靜態查詢;結果集扁平化後需應用層重構樹結構。
MySQL 8.0+、PostgreSQL、SQL Server、Oracle 均支持遞歸 CTE:
WITH RECURSIVE chain AS (
SELECT a.id, a.id_receiveid, b.id_receiveid_old, 1 AS level
FROM table_a a
JOIN table_b b ON a.id_receiveid = b.id_receiveid
WHERE a.id = ? -- 起始節點
UNION ALL
SELECT a.id, a.id_receiveid, b.id_receiveid_old, c.level + 1
FROM chain c
JOIN table_a a ON c.id_receiveid_old = a.id_receiveid
JOIN table_b b ON a.id_receiveid = b.id_receiveid
WHERE c.level < 100 -- 防無限遞歸
)
SELECT * FROM chain;
可通過 Hibernate createNativeQuery() 執行,映射為 DTO 或 Object[]。
public List<ResultDTO> findChain(String startId) {
List<ResultDTO> result = new ArrayList<>();
String currentId = startId;
int depth = 0;
while (currentId != null && depth < 100) { // 防死循環
// 查表 B 獲取 OLD_ID
TableB b = entityManager.createQuery(
"FROM TableB WHERE idReceiveid = :id", TableB.class)
.setParameter("id", currentId)
.getSingleResult();
if (b == null || b.getIdReceiveidOld() == null) break;
// 記錄結果
result.add(new ResultDTO(currentId, b.getIdReceiveidOld()));
// 下一輪查詢
currentId = b.getIdReceiveidOld();
depth++;
}
return result;
}
兩表遞歸關聯查詢,數據庫支持 CTE 時首選原生遞歸查詢,性能最佳且代碼簡潔;不支持 CTE 的舊版本數據庫,可用應用層循環查詢配合緩存優化;Hibernate 左連接適用於固定淺層關聯場景。架構設計時應評估遞歸深度分布,選擇最適合的技術方案。