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

SQL 與 ORM 之爭:從手寫 SQL 到面向對象查詢的架構演進思考

     編輯:Java 綜合教學

SQL 與 ORM 之爭:從手寫 SQL 到面向對象查詢的架構演進思考

早期項目中手寫複雜 SQL 是核心技能,隨著 ORM 框架 (Hibernate/MyBatis/JPA) 普及、領域驅動設計 (DDD) 推廣、微服務拆分,代碼中原生 SQL 比例大幅下降。本文通過權限系統雙案例對比,剖析這一演進的深層動因與工程權衡。

案例背景:RBAC 權限模型

核心表:organization、user、role、menu + 3 張關聯表 (role_menu, role_user, org_user)

場景一:查詢用戶所有菜單

原生 SQL 寫法

SELECT a.uuid, a.name 
FROM menu a 
LEFT JOIN role_menu b ON a.uuid = b.menu_id 
LEFT JOIN role_user c ON b.role_id = c.role_id 
WHERE c.user_id = 'user-uuid';

面向對象查詢 (Repository 模式)

RoleUser roleUser = roleRepository.findByUserId(userId);
if (roleUser == null) throw new BizException("用戶無角色");

List roleMenus = roleRepository.findMenusByRoleId(roleUser.getRoleId());
if (roleMenus.isEmpty()) throw new BizException("角色無菜單");

List menus = roleMenus.stream()
    .map(rm -> menuRepository.findById(rm.getMenuId()))
    .filter(Objects::nonNull)
    .collect(Collectors.toList());

場景二:查詢角色在部門下的用戶

原生 SQL

SELECT a.* 
FROM user a 
LEFT JOIN role_user b ON a.uuid = b.user_id 
LEFT JOIN org_user c ON a.uuid = c.user_id 
WHERE b.role_id = 'role-uuid' AND c.org_id = 'org-uuid';

面向對象查詢

List roleUsers = roleRepository.findUsersByRoleId(roleId);
List orgUsers = orgRepository.findUsersByOrgId(orgId);

Set roleUserIds = roleUsers.stream().map(User::getId).collect(Collectors.toSet());
List result = orgUsers.stream()
    .filter(u -> roleUserIds.contains(u.getId()))
    .collect(Collectors.toList());

深度對比維度

維度手寫 SQLORM/面向對象
可讀性/意圖表達需解析 JOIN/WHERE 邏輯方法名即文檔,業務語義顯性
錯誤定位執行報錯/結果錯,難定位編譯期類型安全,運行期堆棧清晰
重構安全性表/列變更需全文搜索 SQL重構工具自動同步實體/字段
性能可控性完全控制執行計劃需理解框架生成 SQL,必要時介入
N+1 問題不存在易發生,需 fetch join / 批量查詢優化
複雜報表/聚合優勢明顯不適合,建議落庫視圖/物化表
測試友好度需真實數據庫可 Mock Repository 單元測試

架構演進三階段

  1. SQL 中心:DAO 層封裝 SQL,Service 組合 DAO,業務邏輯稀薄
  2. 對象中心 (DDD):聚合根/實體/值對象封裝行為,Repository 抽象持久化,Service 編排領域對象
  3. CQRS 讀寫分離:寫模型 (命令) 保證一致性,讀模型 (查詢) 面向視圖優化,雙模型異步同步

工程決策指南

  • 核心交易/高併發寫入:手寫 SQL + 存儲過程/ShardingSphere,極致性能
  • 標準 CRUD/業務查詢:MyBatis XML / JPA Repository / QueryDSL,開發效率優先
  • 複雜報表/多維分析:ClickHouse/Doris/預計算寬表,完全繞過 ORM
  • 避免極端:既不「全手寫 SQL 炫技」也不「盲目 ORM 導致 N+1 炸庫」

核心洞見

關系數據庫是面向集合的集合論模型,OOP 是面向對象的圖模型。ORM 本質是阻抗失配的妥協橋樑。成熟工程師不執着於工具之爭,而是根據業務複雜度、性能指標、團隊能力、演進階段做動態選擇。

從「撸 SQL」到「撸代碼」,不是技術倒退,而是抽象層級提升:將「如何查」下沉給框架/中間件,業務代碼專注「查什麼、為什麼查、怎麼用結果」。這正是軟件工程「分層、解耦、領域建模」的核心價值體現。

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