Spring Data

目錄

一、Spring Data 簡介與生態概覽

  • 什么是 Spring Data?

  • Spring Data 與 Spring Data JPA 的關系

  • Spring Data 家族:JPA、MongoDB、Redis、Elasticsearch、JDBC、R2DBC……

  • 與 MyBatis 的本質差異(ORM vs SQL 顯式控制)


二、Spring Data JPA 核心機制

  • 實體類(@Entity)與主鍵映射(@Id、@GeneratedValue)

  • Repository 接口機制(CrudRepository / JpaRepository)

  • 方法命名規則自動生成 SQL

  • @Query 注解實現復雜 SQL 查詢

  • 自動分頁與排序(Pageable、Sort)


三、事務傳播與懶加載機制

  • Spring JPA 中的事務管理(@Transactional 原理)

  • 懶加載(Lazy)與事務綁定的陷阱

  • N+1 查詢問題與優化建議

  • 實踐建議:只在業務層操作 Entity,不在 Controller 層觸發懶加載


四、多表關系映射實踐(重點)

  • 一對一、一對多、多對多映射(@OneToOne、@OneToMany、@ManyToMany)

  • 級聯操作與 orphanRemoval

  • 實體關聯的 JSON 序列化問題(@JsonIgnore、DTO 分層)

  • 復雜關系建議:適當拆 DTO,或退回 MyBatis 編排


五、實際使用建議與邊界分析

  • 適合使用 JPA 的典型場景

  • 不適合 JPA 的典型情況(復雜動態 SQL、大批量批處理)

  • 與 MyBatis 混合使用的實踐建議

  • 如何從 MyBatis 轉向 JPA,或二者并存策略


六、常見問題與調試技巧

  • 查詢日志打印(spring.jpa.show-sql / Hibernate SQL log)

  • update/delete 無效?事務提交機制說明

  • SQL 執行效率低?加 @Query 或改為原生 SQL

  • Entity 修改不生效?Session 緩存機制說明


七、Spring Data 面試題精選

  • Spring Data 與 JPA 的關系?

  • Repository 中方法名如何自動生成 SQL?

  • 懶加載為何常出錯?如何解決?

  • 一對多關系中 mappedBy 的含義?

  • Jpa 與 MyBatis 區別?哪個更適合高并發寫入?


一、Spring Data 簡介與生態概覽

Spring Data 是 Spring 團隊推出的數據訪問框架集合,旨在通過統一的方式簡化各種數據源(關系型、文檔型、KV、圖數據庫等)的操作。它提供了聲明式、可擴展的 Repository 接口抽象,屏蔽底層繁瑣的持久化細節。

? Spring Data vs Spring Data JPA

名稱說明
Spring Data統一的數據訪問抽象頂層項目
Spring Data JPA基于 JPA 規范(Hibernate 實現)的子項目

📌 換句話說,Spring Data 是方法論,JPA 是實現方式之一。

🌐 Spring Data 家族生態(不只 JPA)

子項目支持的數據源類型
Spring Data JPAORM(Hibernate、EclipseLink)
Spring Data MongoDB文檔數據庫(Mongo)
Spring Data Redis鍵值存儲
Spring Data Elasticsearch全文檢索引擎
Spring Data JDBC更輕量的 JDBC 操作
Spring Data R2DBC響應式關系數據庫

🔍 與 MyBatis 的本質差異

特性Spring Data JPAMyBatis(Plus)
查詢方式聲明式、自動生成 SQL顯式 SQL 編寫
實體管理自動緩存與生命周期手動管理映射關系
動態 SQL支持較弱(除非用原生查詢)支持強大 XML / 注解 SQL
學習曲線輕度復雜(理解 Entity/關系)寫 SQL 就能用
適合場景簡單 CURD、快速交付高度復雜查詢、控制細節場景

🎯 小結:JPA 優雅但不萬能,場景決定工具,別迷信“自動”。


二、Spring Data JPA 核心機制

Spring Data JPA 最大的優勢在于最少的代碼完成 80% 的數據庫操作。其背后是基于 JPA 規范(通常由 Hibernate 實現)自動管理實體對象生命周期。

1. 實體類定義(@Entity)

@Entity
public class User {@Id@GeneratedValueprivate Long id;
?private String name;
}
  • @Id 標識主鍵,@GeneratedValue 自動生成策略

  • 必須有無參構造函數

2. Repository 接口機制

public interface UserRepository extends JpaRepository<User, Long> {
}
  • 不用寫實現類,Spring 自動為接口生成代理類

  • 繼承 CrudRepository(基礎增刪查改)或 JpaRepository(支持分頁排序)

3. 方法名自動生成 SQL

User findByName(String name);
List<User> findByAgeGreaterThan(int age);
  • 自動推導查詢語句,適合簡單場景

  • ?? 復雜邏輯可讀性差,不建議濫用

4. @Query 注解支持自定義查詢

@Query("SELECT u FROM User u WHERE u.name LIKE %:name%")
List<User> searchByName(@Param("name") String name);
  • 支持 JPQL / 原生 SQL(nativeQuery = true)

  • 推薦使用 @Query 明確邏輯,避免方法名過長

5. 分頁與排序支持

Page<User> findByAge(int age, Pageable pageable);
  • Pageable 可組合 page/size/sort 參數

  • 接口自動接入分頁,簡潔清晰

💡 建議:

  • 簡單查用方法命名,復雜查用 @Query

  • 分頁/排序直接內置,無需寫 SQL,提升開發效率


三、事務傳播與懶加載機制

Spring JPA 默認集成 Spring 的聲明式事務,配合 ORM 的延遲加載特性,帶來了強大但也容易踩坑的行為。

1. 事務控制:@Transactional 注解

@Service
public class UserService {@Transactionalpublic void createUser(...) {// 插入、更新等持久化操作}
}
  • 方法默認使用數據庫事務包裹

  • 支持傳播行為(Propagation)與回滾策略(RollbackFor)

2. 懶加載與事務綁定陷阱

@OneToMany(fetch = FetchType.LAZY)
private List<Order> orders;
  • LAZY:延遲加載,訪問屬性才觸發 SQL

  • 若在事務外訪問,常見錯誤:

org.hibernate.LazyInitializationException: could not initialize proxy

📌 正確做法:

  • 避免在 Controller 層訪問懶加載字段

  • 可在 Service 層 @Transactional 中顯式訪問觸發加載

3. N+1 查詢問題

List<User> users = userRepository.findAll(); // 每個 user 查詢一次 orders
  • 導致大量 SQL,性能極差

  • 解決方案:

    • 使用 @EntityGraph 或 JPQL JOIN FETCH 優化

    • 或使用 DTO 投影只查必要字段

4. 實踐建議

  • Controller 永遠不應該訪問 Entity 懶加載字段

  • Service 層中合理使用事務包裹數據加載邏輯

  • 大量查詢慎用 LAZY,最好 JOIN 提前加載或用 DTO 替代


四、多表關系映射實踐(重點)

JPA 支持標準化的多表映射,非常強大但使用復雜。合理設計可提高開發效率,不合理設計容易導致性能雪崩。

1. 常見關系注解

注解說明
@OneToOne一對一映射(如用戶 → 證件)
@OneToMany一對多映射(如用戶 → 訂單)
@ManyToMany多對多映射(如用戶 ?? 角色)
@OneToMany(mappedBy = "user")
private List<Order> orders;
  • mappedBy 表示由對方維護關系,當前不建外鍵

  • 關聯字段類型建議使用 ListSet

2. 級聯與 orphanRemoval

@OneToMany(cascade = CascadeType.ALL, orphanRemoval = true)
  • cascade:對子對象進行自動保存/更新

  • orphanRemoval:刪除父對象時同步刪除子對象

?? 使用級聯要非常小心,特別是刪除操作。

3. 序列化與 @JsonIgnore

懶加載字段在序列化時容易報錯:

@JsonIgnore // 忽略序列化,避免死循環或 Lazy 異常

或者使用 DTO 將 Entity 轉為展現模型,徹底解耦。

4. 實戰建議

需求類型建議方式
簡單關聯 + 查詢不頻繁可用 JPA 實體映射
多表復雜關聯建議使用 DTO + 原生 SQL(MyBatis)
數據驅動系統更適合 MyBatis 手動控制

📌 結論:JPA 適合建模,MyBatis 適合靈活調度。


當然可以!以下是你提出的后三部分內容,一氣呵成,風格與前文一致,突出實用導向批判性思維工程視角


五、實際使用建議與邊界分析

Spring Data JPA 的確能大幅減少樣板代碼,但也不是銀彈。如何“用得剛剛好”,是實際項目中的關鍵。

? 適合使用 JPA 的典型場景

  • 表結構清晰、字段穩定

  • 標準增刪改查占多數(業務邏輯遠重于查詢邏輯)

  • CRUD 快速開發、原型驗證項目

  • 注重模型完整性(如領域驅動設計 DDD)

📌 例子:用戶系統、CMS、后臺管理系統等。

?? 不適合的典型場景

  • 復雜動態 SQL 查詢(例如多條件組合篩選)

  • 大批量數據操作(insert/update/delete)

  • 頻繁的多表聯查,尤其是需精細控制字段、排序、分頁等

  • 分庫分表等數據庫中間件場景(ShardingSphere、TiDB)

JPA 是 ORM 方案,適合對象建模,不擅長“調 SQL”。

🔁 與 MyBatis 混用建議

JPA 與 MyBatis 并不沖突,關鍵在職責劃分。

功能建議使用
簡單增刪改查JPA(Repository 快速實現)
復雜查詢、數據分析MyBatis / 原生 SQL
分頁、過濾器MyBatis 或 @Query + Pageable

💡實踐案例:

  • 用戶模塊:JPA 實現基本增刪改查

  • 報表模塊:MyBatis 實現復雜聚合統計

🚀 從 MyBatis 向 JPA 轉型?

不要盲目“轉型”,除非你追求更清晰的數據模型、更多的抽象能力。

  • 優先嘗試局部替換,避免“一刀切”

  • JPA 難以替代 MyBatis 的 SQL 靈活性,別追求全局統一


六、常見問題與調試技巧

Spring Data JPA 常見問題很多,底層是 Hibernate,很多坑源自 Session 緩存機制和延遲加載策略。

🐞 查詢日志打印

開發階段開啟 SQL 日志,有助于理解背后執行邏輯:

spring.jpa.show-sql: true
spring.jpa.properties.hibernate.format_sql: true
logging.level.org.hibernate.SQL: DEBUG

想看具體參數值?加:

logging.level.org.hibernate.type.descriptor.sql: TRACE

😵 update/delete 無效?

常見原因:沒有事務提交

@Transactional
public void updateUserName(...) {user.setName("new");// 沒有 save() 也能生效 —— Hibernate 自動臟數據檢查
}

如果沒加 @Transactional,修改會被丟棄!

🐢 SQL 執行慢?

默認是 JPQL 轉換為 SQL,有些操作效率低:

  • 多表聯查用 JPQL 可能生成臃腫 SQL

  • 建議:使用 @Query(nativeQuery=true) 寫原生 SQL

@Query(value = "SELECT * FROM user WHERE name LIKE %?1%", nativeQuery = true)
List<User> search(String name);

🤔 修改數據不生效?

Session 一級緩存機制:

User u = repo.findById(id).get();
u.setName("new");
// 若未 flush/提交,可能不會立即執行 SQL

🧠 Hibernate 會延遲提交直到事務結束或調用 flush。

解決方法:

  • 確保有事務注解

  • 或使用 EntityManager.flush() 強制提交


七、Spring Data 面試題精選

以下是一些常被問到的問題,建議能講得出原理、舉得出例子,不是死記硬背。


1?? Spring Data 與 JPA 的關系?

  • JPA 是 Java EE 標準,Hibernate 是實現

  • Spring Data 是對 JPA 的進一步封裝(Repository 抽象)

📌 JPA 管協議,Spring Data 管開發效率


2?? Repository 方法名如何自動生成 SQL?

  • Spring 解析接口方法名,如 findByNameAndAge

  • 自動生成對應 JPQL:SELECT x FROM Entity x WHERE x.name = ? AND x.age = ?

  • 如果命名超復雜,建議換成 @Query


3?? 懶加載為何常出錯?

  • FetchType.LAZY 要求在事務內訪問

  • Controller 中訪問懶加載字段時,Session 已關閉 → 報錯

? 正確做法:提前在 Service 層加載或用 DTO


4?? mappedBy 是干什么的?

  • 表示關系由對方維護

  • 當前實體不會再創建外鍵

@OneToMany(mappedBy = "user")
private List<Order> orders;

此時外鍵 user_id 由 Order 表維護,User 表不會建列。


5?? Jpa 與 MyBatis 哪個更適合高并發寫入?

  • MyBatis 更適合大批量寫入與性能調優

  • JPA 默認按對象方式提交,批處理較難控制

📌 高并發、極致性能場景優先考慮 MyBatis + 手動 SQL + 事務精細化控制


本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/bicheng/78098.shtml
繁體地址,請注明出處:http://hk.pswp.cn/bicheng/78098.shtml
英文地址,請注明出處:http://en.pswp.cn/bicheng/78098.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

建筑末端配電回路用電安全解決方案

一、電氣火災的嚴峻現狀 根據國家應急管理部消防救援局的數據&#xff0c;電氣火災長期占據各類火災原因之首&#xff0c;2021年占比高達50.4%。其中&#xff0c;末端配電回路因保護不足、監測手段落后&#xff0c;成為火災高發隱患點。私拉電線、線路老化、接觸不良、過載等問…

華為開發崗暑期實習筆試(2025年4月16日)

刷題小記&#xff1a; 第一題懷疑測試樣例不完整&#xff0c;貪心法不應該能夠解決該題。第二題使用0-1BFS解決單源最短路徑的問題&#xff0c;往往搭配雙端隊列實現。第三題是運用動態規劃解決最大不重疊子區間個數的問題&#xff0c;難點在于滿足3重判斷規則&#xff0c;所需…

Rust: 從內存地址信息看內存布局

內存布局其實有幾個&#xff1a;address&#xff08;地址&#xff09;、size&#xff08;大小&#xff09;、alignment&#xff08;對齊位數&#xff0c;2 的自然數次冪&#xff0c;2&#xff0c;4&#xff0c;8…&#xff09;。 今天主要從address來看內存的布局。 說明&…

每日一題算法——兩個數組的交集

兩個數組的交集 力扣題目鏈接 我的解法&#xff1a;利用數組下標。 缺點&#xff1a;當取值范圍很大時&#xff0c;浪費空間。 class Solution { public:vector<int> intersection(vector<int>& nums1, vector<int>& nums2) {int count1[1001]{0…

c++ 互斥鎖

為練習c 線程同步&#xff0c;做了LeeCode 1114題. 按序打印&#xff1a; 給你一個類&#xff1a; public class Foo {public void first() { print("first"); }public void second() { print("second"); }public void third() { print("third"…

山東大學軟件學院創新項目實訓開發日志(20)之中醫知識問答自動生成對話標題bug修改

在原代碼中存在一個bug&#xff1a;當前對話的標題不是現有對話的用戶的第一段的前幾個字&#xff0c;而是歷史對話的第一段的前幾個字。 這是生成標題的邏輯出了錯誤&#xff1a; 當改成size()-1即可

WSL2-Ubuntu22.04下拉取Docker MongoDB鏡像并啟動

若未安裝docker可參考此教程&#xff1a;可以直接在wsl上安裝docker嗎&#xff0c;而不是安裝docker desktop&#xff1f;-CSDN博客 1. 拉取鏡像 docker pull mongo:latest 2.打開網絡加速&#xff0c;再次拉取鏡像 3.創建docker-compose.yml 進入vim編輯器后輸入i進行編輯&a…

中通 Redis 集群從 VM 遷移至 PVE:技術差異、PVE 優劣勢及應用場景深度解析

在數字化轉型浪潮下&#xff0c;企業對服務器資源的高效利用與成本控制愈發重視。近期&#xff0c;中通快遞將服務器上的 Redis 集群服務從 VM&#xff08;VMware 虛擬化技術&#xff09;遷移至 PVE&#xff08;Proxmox VE&#xff09;&#xff0c;這一技術舉措引發了行業廣泛關…

Prometheus+Grafana實時監控系統各項指標

一、監控架構設計 核心組件與數據流 Prometheus&#xff1a;時序數據采集、存儲與告警規則管理Node Exporter&#xff1a;采集主機指標&#xff08;CPU、內存、磁盤、網絡等&#xff09;數據庫Exporter&#xff1a;如 mysqld_exporter、postgres_exporterGrafana&#xff1a;…

[密碼學基礎]GMT 0029-2014簽名驗簽服務器技術規范深度解析

GMT 0029-2014簽名驗簽服務器技術規范深度解析 引言 在數字化轉型和網絡安全需求激增的背景下&#xff0c;密碼技術成為保障數據完整性與身份認證的核心手段。中國密碼管理局發布的GMT 0029-2014《簽名驗簽服務器技術規范》&#xff0c;為簽名驗簽服務器的設計、開發與部署提…

多路轉接select服務器

目錄 select函數原型 select服務器 select的缺點 前面介紹過多路轉接就是能同時等待多個文件描述符&#xff0c;這篇文章介紹一下多路轉接方案中的select的使用 select函數原型 #include <sys/select.h> int select(int nfds, fd_set *readfds, fd_set *writefds, f…

QT6 源(45):分隔條 QSplitter 允許程序的用戶修改布局,程序員使用 IDE時,就是分隔條的用戶,以及其 QSplitter 源代碼

&#xff08;1&#xff09; &#xff08;2&#xff09;本類的繼承關系如下&#xff0c;所以說分隔條屬于容器&#xff1a; &#xff08;3&#xff09;本類的屬性&#xff1a; &#xff08;4&#xff09; 這是一份 QSplitter 的舉例代碼&#xff0c;注意其構造函數時候的傳參&am…

VSCode PIO使用Jlink SWD燒錄Stm32

一、背景 PIO的編譯速度比Arduino快很多&#xff0c;同樣支持Arduino的語法。VScode的自動補全和插件也能夠幫助快速開發目前使用JLINK SWD的方式連接STM32 二、配置 在ini配置文件中&#xff0c;添加如下內容 [env:genericSTM32F103C8] platform ststm32 board genericS…

JavaScript 渲染內容爬取:Puppeteer 入門

在現代網絡應用中&#xff0c;許多網頁內容是通過 JavaScript 渲染生成的&#xff0c;傳統的爬蟲工具往往難以獲取這些動態內容。Puppeteer 作為一種強大的瀏覽器自動化工具&#xff0c;為這一問題提供了優雅的解決方案。本文將帶你入門 Puppeteer&#xff0c;介紹如何安裝、啟…

卷積神經網絡:視覺煉金術士的數學魔法

引言&#xff1a;當數學遇見視覺煉金術 在人工智能的奇幻世界里&#xff0c;卷積神經網絡&#xff08;CNN&#xff09;猶如掌握視覺奧秘的煉金術士&#xff0c;將原始像素的"鉛塊"淬煉成認知的"黃金"。這種融合數學嚴謹性與生物靈感的算法架構&#xff0c…

Android Cordova 開發 - Cordova 快速入門(Cordova 環境配置、Cordova 第一個應用程序)

一、Cordova 1、Cordova 概述 Cordova 是使用 HTML&#xff0c;CSS 和 JavaScript 構建混合移動應用程序的平臺 2、Cordova 特征 &#xff08;1&#xff09;命令行界面&#xff08;Cordova CLI&#xff09; 這是可用于啟動項目&#xff0c;構建不同平臺的進程&#xff0c;…

ubuntu18.04啟動不了修復

參考: 虛擬機里的Ubuntu18.4啟動時進入到grub rescue救援模式&#xff08;無法正常進入到系統&#xff09;&#xff0c;ls查看后只有一個硬盤和分區&#xff0c;且無法找到/boot/grub文件【已解決】_ubuntu grub rescue-CSDN博客 本人fdisk錯誤使用,導致了grub啟動不了 第一步…

SpringBoot3設置maven package直接打包成二進制可執行文件

注意事項 SpringBoot普通native打包順序clean compile spring-boot:process-aot native:compile 使用以下配置只會的打包順序clean package&#xff08;注意&#xff1a;使用此配置以后打包會有編譯后的class文件、jar包、original源文件、二進制可執行文件【Linux是無后綴的包…

【華為】防火墻雙擊熱備-之-主備模式-單外網線路

FW1和FW2的業務接口都工作在三層&#xff0c;上行連接二層交換機。上行交換機連接運營商的接入點&#xff0c;運營商為企業分配的IP地址為100.100.100.2。現在希望FW1和FW2以主備備份方式工作。正常情況下&#xff0c;流量通過FW1轉發&#xff1b;當FW1出現故障時&#xff0c;流…

MYSQL之表的操作

1. 創建表 語法: CREATE TABLE table_name ( field1 datatype, field2 datatype, field3 datatype ) character set 字符集 collate 校驗規則 engine 存儲引擎; field 表示列名, datatype 表示列的類型character set 字符集, 如果沒有指定字符集, 則以所在數據庫的字符集為…