數據訪問層(DAL)技術已經非常成熟,從最早的 JDBC 到 Hibernate、MyBatis,再到 Spring Data JPA。我們習慣了用這些框架處理數據。然而,當我們把目光投向“數據”本身的變化時,會發現這些經典的框架似乎正逐漸變為“老一代”。
新一代的挑戰不再僅僅是如何優雅地寫 SQL,而是如何用統一的方式訪問那些不再僅僅存儲在關系型數據庫中的數據。
老舊的一代
談論“老一代”數據訪問庫,并非貶義,而是指它們誕生的時代背景和核心使命。
在過去以及現在,MyBatis、Hibernate、JPA (Hibernate)、Spring JDBC Template 以及 Apache Commons DbUtils 統治了 Java 開發者的工具箱。它們的共同特征非常明顯:
關系型數據庫
它們的設計初衷就是為了更好地操作 Oracle, MySQL, PostgreSQL 等數據庫。核心邏輯無論是 ORM 映射還是 SQL 模板,都緊緊圍繞著 SQL 標準。
專有性
當 NoSQL 興起后,這些框架顯得力不從心。于是我們看到了 MongoDB Java Driver、Elasticsearch RestHighLevelClient 等專有 SDK。
這種格局導致了一個現象:要么專有,要么偏向純關系型數據庫。如果你的應用既要查 MySQL 也要查 Elasticsearch,你通常需要引入兩套完全不同的技術棧,寫兩套風格迥異的代碼。
破舊嘗試
數據庫技術一直在不斷的迭代,文檔型數據庫(MongoDB)、搜索引擎(Elasticsearch/OpenSearch)、鍵值存儲(Redis)、時序數據庫乃至現在的向量數據庫蜂擁而至。
面對這些 “新東西”,我們熟悉的“老配方”也在嘗試去解決新問題。于是我們看到了一系列試圖彌合裂痕的動作:
Hibernate OGM
試圖將 JPA 標準延續到 NoSQL 領域,用注解映射非關系型數據。
Spring Data
通過統一的 Repository 接口抽象,試圖掩蓋底層實現的差異(如JpaRepository與MongoRepository)。
Easy-ES
試圖用 MyBatis-Plus 的習慣去操作 Elasticsearch,讓開發者像操作數據庫表一樣操作索引。
然而,這些努力雖然緩解了問題,但依然難以掩蓋核心的困境:
套用 SQL 思維: SQL 是關系型數據庫的通用語,但對于具有嵌套結構、倒排索引或圖關系的數據,強行套用 SQL 或表格思維。 像 Easy-ES 這樣的工具雖然方便,但在處理 ES 特有的聚合或復雜 DSL 時,往往還是需要回退到原生 QueryDSL。
中間件對 JDBC 的態度: JDBC 本是 Java 屆最成功的抽象之一,但它被打上了深深的關系型數據庫烙印。
API 接口層面的持續割裂: 盡管有 Spring Data 這樣的封裝,但底層的割裂依然存在。
這種割裂不僅增加了學習成本,更讓架構設計變得復雜。我們看似有了一堆工具,但依然沒有一個真正的“One API”來統一所有數據訪問。
One API Access Any DataBase
既然已經走向多元化,數據訪問層(DAL)也必須進化。新一代數據訪問庫的使命,應當是讓數據訪問重新實現標準化和統一化。
我們不再應該問“這是什么數據庫?”,而應該問“我想在這個數據源上做什么操作?”。
繼承 JDBC 和 SQL 的普世精神,但打破其對關系型數據庫的枷鎖,這就是新一代數據訪問庫的目標。將其概括為一句就是:"One API Access Any DataBase"。
技術選擇與可行路徑
要實現這個宏大的愿景,技術上有兩條主要路徑可供選擇:
路徑 1:統一 DSL
這條路試圖定義一種“萬能語言”,能同時表達關系查詢、文檔檢索、圖遍歷等邏輯。
類似 SQL 的統一 DSL: 本質的難點在于應用場景的不同,導致很難有一個統一的 DSL 能在所有場景下適用。比如 Oracle、MongoDB、Elasticsearch 甚至是 Redis 在語法層面達成共識。
自然語言: 一種更大膽的假設,基于 LLM 大語言模型直接將自然語言解釋為數據庫引擎可執行的物理執行計劃,也就是:自然語言 -> AI -> 算子樹 -> 存儲引擎, AI 在這一過程中充當了 Parser 和 Optimizer 的角色,直接驅動數據庫內核運行具體的物理任務。但在當下,AI 在處理語義精確性、數據訪問安全性以及復雜邏輯推理時仍存在“幻覺”風險。 將不確定的 AI 推理直接作用于確定性的數據存儲內核,這將會是一場極具冒險的行為。因此,它更多被視為輔助工具(Copilot),而非底層的、確定性的數據訪問標準。
路徑 2:基本范式的抽象
操作(Operation)是數據訪問的本質。相比發明新語言或依賴 AI,顯得更加務實且可控。無論數據存在 MySQL 的行、Redis 的 Key、Elasticsearch 的 Document、還是 Neo4j 的節點。
應用程序對數據的使用場景絕大多數時候都逃不出增(Create)、刪(Delete)、改(Update)、查(Read)這四個基本范式。
行為為中心: 不同于 SQL 關注“如何描述數據”,統一 API 關注“應用想對數據做什么”。“根據 ID 獲取對象”是一個通用的意圖,無論底層是SELECT * FROM table WHERE id=?還是GET /index/_doc/id,其業務語義是完全一致的。
逃生艙(Escape Hatch): 當然,如果僅有簡單的 CRUD 是無法覆蓋真實業務中 20% 的復雜場景(如深度聚合、圖算法分析)。因此,統一 API 方案必須包含一個逃生艙機制。 當標準 CRUD 無法滿足需求時,開發者可以借助 JDBC 的Statement接口,直接下發專有 DSL(如 Elasticsearch JSON Query)或標準化 SQL。 底層的適配器不僅負責翻譯標準 CRUD,也允許透傳原生 API 或 SDK 調用,確保簡單場景統一化,復雜場景如初般強大。
適配器模式: 通過定義一套標準的 API(如insert,update,query),我們可以在底層通過適配器模式,將這些標準請求動態 “翻譯” 為不同數據源的方言(Dialect)。
新一代數據訪問庫
我認為“新一代 Java 數據訪問庫”應該具是以 One API Access Any DataBase 為核心愿景,通過標準化的 API 屏蔽底層數據源的差異,為開發者提供統一、簡單、高效的數據操作體驗為目標。
它不應再區分“這是 ORM”還是“這是 Client”,它就是應用通往數據的統一大門。
dbVisitor 的技術嘗試
dbVisitor正是基于這一理念誕生的技術嘗試。它的架構設計非常獨特,可以概括為:API訪問庫 + JDBC Driver的雙層適配架構。
API訪問庫:提供統一 API
dbVisitor 的數據訪問層不依賴于具體的 SQL 語法,而是提供高度抽象的 API。例如:查詢構造器
![]()
這一層負責屏蔽 Java 對象與數據模型之間的映射差異。
在此過程中,方言(Dialect)扮演了關鍵的翻譯官角色。它負責根據上層統一 API 的調用行為(如.list(),.eq()),生成目標數據源能夠理解的專有 DSL(如 MySQL 的 SQL、MongoDB 的 BSON Command、Elasticsearch 的 JSON DSL)。
這些生成的 DSL 隨后會被下發到JDBC Driver 適配層,由對應的驅動執行器完成最終的數據交互。這種機制確保了業務代碼的純凈性,同時保留了對底層特性的精確控制。
JDBC Driver 適配器
標準下的選擇性實現,這是 dbVisitor 最具創新性的地方。它沒有重新發明輪子去寫一套私有協議的 Driver,而是選擇復用 JDBC 標準接口,但對其內涵進行了擴展和適配。
dbVisitor 的解法是引入一個輕量級的驅動適配器框架。它將 JDBC 繁瑣的狀態管理和復雜的接口規范,封裝為簡單的Request/Response 模型。
開發者不需要去實現一個完整的 JDBC 規范,只需要關注核心的數據交互邏輯,并實現Request/Response 模型即可。
這種簡化極大降低了適配新數據源的成本,從而能夠快速適配絕大多數的數據訪問需求。
通過這種“舊瓶裝新酒”的方式,dbVisitor 既保留了 JDBC 生態的兼容性(你可以直接用 Druid 連接池管理 ES 連接),又實現了對 NoSQL 的原生級支持。
目前的挑戰
盡管 dbVisitor 的雙層適配架構解決了大部分通用問題,但在實現 "One API" 的征途中,我們依然面臨著一些客觀存在的挑戰:
封裝與穿透: Request/Response 模型可以極大地簡化了適配器開發,但沒有任何一種抽象能完美覆蓋所有底層特性。當開發者需要使用某個數據源極其特殊的特性時, 目前的解法是允許使用 JDBC 的unwrap方法直達底層 SDK。雖然這在一定程度上破壞了封裝性,不作為推薦用法,通過這種“開后門”的方式,保證了在極端場景下問題依然可解。
DSL 困境: 并非所有 NoSQL 都有完善的查詢語言,對于那些沒有標準 DSL 的數據庫,dbVisitor 不得不采用一種折中方案:用 DSL 語法來模仿 SDK 的 API 調用結構。 這樣做的好處是保留了近似官方的習慣用法,降低了認知門檻。但壞處也很明顯:不同版本的 SDK API 差異甚至是不兼容的 API 結構。 這會削弱了 DSL 本身的標準化程度和穩定性,加重認知負擔。這個問題只能寄希望于數據庫廠商可以有一個屬于它自己的標準的查詢語法出現,例如 Elasticsearch 的 QueryDSL。
最佳實踐總結:
經過大量的適配實踐,我發現實現"One API"的最佳路徑,是依賴于數據庫廠商提供的標準 DSL 或 Shell Commands。
如果數據庫本身提供了一套穩定的文本協議(如 SQL, MongoDB Shell Command, Elasticsearch DSL),那么基于這些標準協議構建適配器,對接底層 API,是最穩健、兼容性最好的方式。
對于沒有 DSL 的 數據庫,只需要模仿它 API 的調用方式,提供一個 Shell Command,這一點可以借鑒 MongoDB 的思路。
dbVisitor 實戰演示
為了讓大家更直觀地感受"One API"的魅力,以最常見的 CRUD 操作為例,展示 dbVisitor 如何在不同數據源間保持統一的編碼體驗。
1. 統一的 CRUD 體驗
無論底層是MySQL、MongoDB還是Elasticsearch,開發者都可以使用完全一致的 API 進行數據操作。
![]()
2. 底層 API 可達 (Escape Hatch)
當統一 API 無法滿足特殊需求時(例如 Redis 的特定原子操作,或 ES 的特殊聚合),dbVisitor 允許通過unwrap機制“穿透”到底層驅動,直接使用原生 SDK。
![]()
dbVisitor 的生態現狀
目前,dbVisitor 已經實現了對多類數據源的統一訪問支持,正在一步步踐行新一代數據訪問庫的承諾:
關系型數據庫:MySQL, PostgreSQL, Oracle, SQLServer, H2, SQLite 等。
NoSQL 支持:Elasticsearch、MongoDB、Redis
在 dbVisitor 的世界里,開發者不再需要為了引入一個新的中間件而重構整個數據訪問層代碼。One API, Access Any DataBase,這不僅僅是一句口號。
如果你對這個項目非常感興趣不妨“加個關注”及對我支持一下。
特別聲明:以上內容(如有圖片或視頻亦包括在內)為自媒體平臺“網易號”用戶上傳并發布,本平臺僅提供信息存儲服務。
Notice: The content above (including the pictures and videos if any) is uploaded and posted by a user of NetEase Hao, which is a social media platform and only provides information storage services.