Spring Data JPA:入門、實戰與進階
內容描述
本書主要分為四個模塊,共33章。
模塊一主要從基本語法的視角,來詳細介紹 Spring Data JPA 的語法糖有哪些,
包括源碼的剖析、實際工作中的經驗分享,以及作者對此的思考、啟發。
模塊二從實際工作中的複雜應用場景開始,依次講解自定義場景,
如何擴展 Spring 給我們提供的框架、數據源、連接、事務之間的關係,
幫助讀者解決實踐中可能會遇到的問題,並學會獨立思考、穩妥解決。
模塊三講解了實際工作遇到的經典問題,如 N+1 sql、lazy、
事務的問題,及作者對此的思考和解決思路。
模塊四從 Spring Data Rest、Spring Data ES、測試用例的角度,
擴展思路,展望一下發展方向。
目錄大綱
前 言
第一部分 基礎知識
第1章 初識Spring Data JPA 2
1.1 Spring Boot和JPA演示 2
1.2 JPA如何整合MySQL數據庫 8
1.2.1 切換MySQL數據源 8
1.2.2 Spring Data JPA測試用例的寫法 10
1.3 整體認識JPA 11
1.3.1 市場上ORM框架的對比 11
1.3.2 JPA簡介和開源實現 12
1.4 認識Spring Data 13
1.4.1 Spring Data簡介 13
1.4.2 Spring Data的子項目 14
1.5 本章小結 15
第2章 全面掌握Spring Data Commons之Repository 16
2.1 Spring Data Commons的依賴關係 16
2.2 Repository接口 17
2.2.1 查看Repository源碼 17
2.2.2 Repository類層次關係 17
2.2.3 Repository接口的實際案例 19
2.3 CrudRepository接口 21
2.4 PagingAndSortingRepository接口 23
2.4.1 PagingAndSortingRepository的源碼 23
2.4.2 PagingAndSortingRepository的使用案例 24
2.5 JpaRepository接口 25
2.6 Repository的實現類SimpleJpaRepository 26
2.7 Repository接口的啟發 27
2.8 本章小結 28
第3章 定義查詢方法的命名語法與參數 29
3.1 定義查詢方法的配置和使用方法 29
3.1.1 直接通過方法名實現CRUD步驟 30
3.1.2 選擇性暴露CRUD方法 30
3.2 方法的查詢策略設置 31
3.3 定義查詢方法的語法 32
3.3.1 語法剖析 32
3.3.2 關鍵源碼 34
3.4 特定類型的參數:Sort和Pageable 36
3.5 限制查詢結果:First和Top 38
3.6 @NonNull、@NonNullApi和@Nullable關鍵字 38
3.7 給我們的一些思考 39
3.8 本章小結 43
第4章 利用Repository中的方法返回值來解決實際問題 44
4.1 Repository的返回結果 44
4.1.1 自定義Streamable 46
4.1.2 返回結果類型List/Stream/Page/Slice 46
4.1.3 Repository對Feature/CompletableFuture異步返回結果的支持 52
4.1.4 對Reactive的支持:Flux與Mono 53
4.1.5 小結 53
4.2 最常見的DTO返回結果的支持方法 56
4.2.1 Projections概念 56
4.2.2 第一種方法:新建一張表的不同Entity 57
4.2.3 第二種方法:直接定義一個UserOnlyNameEmailDto 58
4.2.4 第三種方法:返回結果是一個POJO的接口 60
4.2.5 寫查詢方法的一個小技巧 62
4.3 本章小結 62
第5章 @Query語法詳解及其應用 63
5.1 快速體驗@Query的方法 63
5.2 JpaQueryLookupStrategy關鍵源碼剖析 64
5.3 @Query的基本用法 66
5.3.1 JPQL的語法 67
5.3.2 @Query的用法案例 68
5.3.3 @Query的排序 68
5.3.4 @Query的分頁 69
5.3.5 @Param的用法 70
5.4 @Query之Projections應用返回指定DTO 70
5.4.1 利用UserDto類 72
5.4.2 利用UserDto接口 73
5.5 @Query動態查詢解決方法 74
5.6 本章小結 77
第6章 @Entity的常用註解及Java多態場景應用 78
6.1 JPA協議中關於實體的相關規定 78
6.2 實體裡面常見的註解 79
6.3 生成註解的小技巧 85
6.4 聯合主鍵 86
6.4.1 如何通過@IdClass實現聯合主鍵 86
6.4.2 @Embeddable與@EmbeddedId註解的使用 88
6.5 如何實現實體之間的繼承關係 89
6.5.1 @Inheritance(strategy = InheritanceType.SINGLE_TABLE) 90
6.5.2 @Inheritance(strategy = InheritanceType.JOINED) 91
6.5.3 @Inheritance(strategy = InheritanceType.TABLE_PER_CLASS) 93
6.5.4 關於繼承關係的經驗之談 94
6.6 本章小結 95
第7章 實體之間關聯關係註解的正確使用 96
7.1 @OneToOne 96
7.1.1 @OneToOne的源碼解讀 98
7.1.2 mappedBy的注意事項 99
7.1.3 CascadeType的用法 99
7.1.4 orphanRemoval的屬性用法 100
7.1.5 主鍵和外鍵都是同一個字段 101
7.1.6 @OneToOne延遲加載下只需要ID值 102
7.1.7 @OneToOne的實踐 104
7.2 @JoinCloumns和@JoinColumn 105
7.3 @ManyToOne和@OneToMany 106
7.4 @ManyToMany 110
7.4.1 利用@ManyToOne和@OneToMany表達多對多的關聯關係 112
7.4.2 @ManyToMany的實踐 114
7.5 本章小結 114
第8章 Jackson在實體裡面的註解詳解 115
8.1 Jackson的基本語法 115
8.1.1 三個核心模塊 116
8.1.2 Jackson提供的擴展jar包 116
8.1.3 Jackson中常用的一些註解 117
8.1.4 實例 118
8.2 Jackson和Spring的關係 121
8.2.1 應用場景一:Spring MVC的View層 121
8.2.2 應用場景二:Open-Feign 121
8.2.3 應用場景三:Redis裡面 122
8.2.4 應用場景四:JMS消息序列化 122
8.3 Jackson的原理分析 123
8.3.1 Jackson的可見性原理分析 123
8.3.2 反序列化最重要的方法 124
8.3.3 Module的加載機制 126
8.4 Jackson與JPA常見的問題 127
8.4.1 如何解決死循環問題 127
8.4.2 JPA實體JSON序列化的常見報錯及解決方法 128
8.4.3 推薦的配置項 129
8.4.4 JSON序列化和Java序列化 131
8.5 本章小結 131
第二部分 高階用法與實例
第9章 QueryByExampleExecutor的用法和原理分析 135
9.1 QueryByExampleExecutor的用法 135
9.1.1 基本方法 135
9.1.2 使用案例 136
9.2 QueryByExampleExecutor的語法 140
9.2.1 Example的語法詳解 140
9.2.2 ExampleMatcher方法概述 141
9.2.3 初始化ExampleMatcher實例的方法 142
9.2.4 ExampleMatcher的語法 143
9.2.5 ExampleMatcher的完整例子 145
9.2.6 使用QueryByExampleExecutor時需要考慮的因素 146
9.3 QueryByExampleExecutor的實現原理 146
9.3.1 QueryByExampleExecutor的源碼分析 146
9.3.2 JpaSpecificationExecutor的接口結構 148
9.3.3 通過QBE反向思考JpaSpecificationExecutor 149
9.4 本章小結 149
第10章 JpaSpecificationExecutor的實現原理 150
10.1 JpaSpecificationExecutor的使用案例 150
10.2 JpaSpecificationExecutor的語法詳解 154
10.2.1 Root root 156
10.2.2 CriteriaQuery<?> query 156
10.2.3 CriteriaBuilder 157
10.3 JpaSpecificationExecutor的原理分析 158
10.4 JpaSpecificationExecutor實戰 160
10.4.1 自定義MySpecification 161
10.4.2 利用Specification創建以search為查詢條件的RESTful API 163
10.5 本章小結 165
第11章 Querydsl在JPA中的應用 166
11.1 Querydsl快速入門 166
11.2 Querydsl的語法 170
11.2.1 QuerydslPredicateExecutor 170
11.2.2 QuerydslBinderCustomizer 172
11.2.3 類型安全的應用 174
11.3 Querydsl對WebMVC的支持
及源碼分析 175
11.3.1 @QuerydslPredicate註解 175
11.3.2 QuerydslPredicateArgument-
Resolver源碼分析 177
11.4 本章小結 179
第12章 如何自定義Repository 180
12.1 EntityManager簡介 180
12.1.1 EntityManager的常用方法 180
12.1.2 EntityManager的使用 182
12.2 @EnableJpaRepositories詳解 183
12.2.1 @EnableJpaRepositories的語法 183
12.2.2 @EnableJpaRepositories的默認加載方式 185
12.3 自定義Repository的實現類的方法 186
12.3.1 第一種方法:定義獨立的Repository的Impl實現類 186
12.3.2 第一種方法的原理分析 187
12.3.3 第二種方法:通過@EnableJpaRepositories定義默認的實現類 190
12.3.4 第二種方法的原理分析 192
12.4 實際應用場景 193
12.5 本章小結 193
第13章 JPA的Auditing功能 194
13.1 Auditing是什麼 194
13.2 如何實現Auditing 195
13.2.1 第一種方式:直接在實例裡面添加上述四個註解 195
13.2.2 第二種方式:在實體裡面實現Auditable接口 198
13.2.3 第三種方式:利用@MappedSuperclass註解 200
13.3 JPA的Auditing功能解決了哪些問題 201
13.4 Auditing的實現原理 202
13.4.1 Auditing的源碼分析 202
13.4.2 結論 204
13.5 本章小結 205
第14章 @Entity回調方法的正確使用 206
14.1 Java Persistence API規定的回調方法 206
14.1.1 Entity的回調事件註解 206
14.1.2 語法注意事項 207
14.2 JPA回調註解的使用方法 207
14.2.1 第一種用法:在實體和super-class中使用 207
14.2.2 第二種用法:自定義EntityListener 212
14.2.3 關於@EntityListeners加載順序的說明 214
14.3 JPA回調註解的實踐 214
14.4 JPA回調註解的實現原理和事件機制 216
14.5 本章小結 217
第15章 樂觀鎖機制和重試機制在實戰中的應用 218
15.1 什麼是樂觀鎖 218
15.2 樂觀鎖的實現方法 218
15.2.1 @Version的用法 219
15.2.2 @Version對Save方法的影響 222
15.3 isNew判斷的邏輯 222
15.4 樂觀鎖機制和重試機制的實戰 224
15.4.1 重試機制詳解 224
15.4.2 @Retryable的詳細用法 225
15.4.3 樂觀鎖+重試機制的實踐 227
15.5 悲觀鎖的實現 227
15.6 本章小結 228
第16章 JPA對Web MVC開發的支持 229
16.1 DomainClassConverter組件 230
16.1.1 一個實例 230
16.1.2 源碼分析 231
16.2 Page和Sort的參數支持 233
16.2.1 一個實例 233
16.2.2 原理分析 235
16.3 Web MVC的參數綁定 236
16.3.1 一個實例 237
16.3.2 原理分析 238
16.4 Querydsl的Web MVC支持 239
16.4.1 一個實例 239
16.4.2 原理分析 241
16.5 @DynamicUpdate和
@DynamicInsert詳解 242
16.5.1 通過語法快速了解 242
16.5.2 使用案例 243
16.5.3 只更新非Null的字段 246
16.5.4 @DynamicUpdate與@LastModifiedDate一起使用 248
16.6 Spring Data對系統監控的支持 248
16.7 本章小結 249
第17章 自定義HandlerMethod-ArgumentResolver 250
17.1 Page和Sort參數 250
17.2 HandlerMethodArgumentResolver的用法 252
17.2.1 HandlerMethodArgument-Resolver詳解 252
17.2.2 與HttpMessageConverter的關係 254
17.2.3 HttpMessageConverter的執行順序 254
17.3 HandlerMethodArgumentResolver實戰 255
17.3.1 自定義HandlerMethod-ArgumentResolver 256
17.3.2 實際工作中的四種常見場景 259
17.4 思路拓展 261
17.4.1 WebMvcConfigurer介紹 261
17.4.2 對JSON的返回結果進行統一封裝 262
17.5 本章小結 264
第18章 DataSource詳解及其加載過程 265
18.1 數據源是什麼 265
18.1.1 DataSource源碼分析 266
18.1.2 數據源、驅動、連接和連接池的關係 268
18.2 數據源的加載原理和過程 269
18.2.1 DataSourceAutoConfiguration數據源的加載過程分析 269
18.2.2 Hikari數據源下的MySQL配置實踐 274
18.2.3 Hikari數據通過Prometheus的監控指標應用 276
18.3 AliDruidDataSource的配置與介紹 278
18.4 命名策略詳解及其實踐 279
18.4.1 Hibernate 5的命名策略 279
18.4.2 加載原理與自定義方法 282
18.4.3 實際應用場景 283
18.5 數據庫的時區問題 283
18.5.1 MySQL時間類型字段和時區的關係 283
18.5.2 MySQL驅動處理時區的原理 285
18.6 本章小結 286
第19章 生產環境多數據源的處理方法 287
19.1 第一種方式:@Configuration配置方法 287
19.1.1 通過多個@Configuration的配置方法 287
19.1.2 DataSource與Transaction-Manager、EntityManager-Factory的關係分析 294
19.1.3 默認的JpaBaseConfiguration的加載方式分析 294
19.2 第二種方式:利用Abstract-RoutingDataSource配置 295
19.2.1 利用AbstractRoutingData-Source的配置方法 296
19.2.2 微服務下多數據源的思考 299
19.2.3 微服務下的實戰建議 300
19.3 本章小結 300
第20章 事務、連接池之間的關係與配置 301
20.1 事務的基本原理 301
20.1.1 四種MySQL事務的隔離級別 302
20.1.2 MySQL中事務與連接的關係 303
20.2 Spring事務的配置方法 304
20.2.1 默認@Transactional註解式事務 305
20.2.2 @Transactional的局限性 307
20.2.3 TransactionTemplate的用法 308
20.2.4 自定義TransactionHelper 310
20.2.5 AspectJ事務配置 310
20.2.6 通過日誌分析配置方法的過程 311
20.3 Spring事務的實現原理 313
20.3.1 Spring事務源碼分析 313
20.3.2 事務和連接池在JPA中的注意事項 318
20.4 本章小結 318
第三部分 原理在實戰中的應用
第21章 JPA中的Hibernate加載過程與配置項 320
21.1 Hibernate架構分析 320
21.2 Hibernate 5在Spring Boot 2中的加載過程 321
21.2.1 JpaProperties屬性 322
21.2.2 HibernateJpaConfiguration分析 323
21.2.3 自動加載過程類之間的關係 328
21.3 Repositories的加載模式 329
21.4 在調試時需要的日誌配置 331
21.5 本章小結 333
第22章 理解Persistence Context的核心概念 334
22.1 Persistence Context相關核心概念 334
22.1.1 EntityManagerFactory和Persistence Unit 334
22.1.2 EntityManager和PersistenceContext 335
22.2 實體對象的生命週期 337
22.2.1 第一種:New狀態 337
22.2.2 第二種:Detached狀態 338
22.2.3 第三種:Managed狀態 339
22.2.4 第四種:Removed狀態 339
22.3 解密EntityManager的f lush()方法 340
22.3.1 Flush的作用 340
22.3.2 Flush機制 341
22.3.3 Flush會改變SQL的執行順序 342
22.3.4 Flush與事務提交的關係 343
22.3.5 Flush與樂觀鎖的關係 344
22.3.6 saveAndFlush和save的區別 345
22.4 Dirty判斷邏輯及其作用 346
22.4.1 Dirty效果的例子 346
22.4.2 Entity判斷Dirty的過程 346
22.5 本章小結 347
第23章 Session的open-in-view對事務的影響 348
23.1 Session是什麼 348
23.1.1 對Session的理解 348
23.1.2 SessionImpl解決了什麼問題 349
23.2 open-in-view是做什麼的 350
23.2.1 open-in-view的作用 350
23.2.2 OpenEntityManagerInView-Interceptor源碼分析 351
23.2.3 EntityManager的開啟時機及擴展場景 353
23.2.4 驗證EntityManager創建和釋放的日誌 354
23.3 hibernate.connection.handling_mode詳解 356
23.3.1 PhysicalConnectionHandling-Mode的五種模式 356
23.3.2 默認模式及其修改 358
23.3.3 handling_mode的配置對連接的影響 359
23.4 Session、EntityManager、Connection和Transaction之間的關係 361
23.4.1 Connection和Transaction 361
23.4.2 EntityManager、Connection和Transaction 362
23.4.3 Session、EntityManager、Connection和Transaction 362
23.4.4 Session和Transaction 362
23.5 本章小結 362
第24章 如何在CompletableFuture異步線程中正確使用JPA 363
24.1 CompletableFuture的實際使用案例 363
24.1.1 CompletableFuture的常見寫法 363
24.1.2 案例中表現出來的問題現狀 364
24.2 異步方法步驟拆解 365
24.2.1 CompletableFuture實踐 365
24.2.2 通過日誌查看事務的執行過程 367
24.2.3 異步事務的正確使用方法 369
24.2.4 Session機制與Repository.save(entity)的關係 372
24.3 異步場景下的思考 374
24.4 本章小結 375
第25章 為什麼總會遇到LAZY異常 376
25.1 什麼是LazyInitialization-Exception 376
25.2 LAZY加載機制的原理分析 378
25.2.1 PersistentCollection集合類 378
25.2.2 以PersistentBag為例詳解原理 379
25.3 LAZY異常的常見場景與解決方法 382
25.3.1 場景一:跨事務或事務之外 382
25.3.2 場景二:異步線程 384
25.3.3 場景三:Controller直接返回實體 384
25.3.4 場景四:自定義的攔截器和Filter中無意的toString操作 385
25.4 hibernate.enable_lazy_load_no_trans配置 386
25.5 Javax.persistence.Persistence-Exception異常類型 386
25.6 本章小結 387
第26章 如何正確解決經典的“N+1”SQL問題 388
26.1 什麼是“N+1”SQL問題 388
26.2 減少N對應的SQL語句的條數 393
26.2.1 hibernate.default_batch_fetch_size配置 393
26.2.2 @BatchSize註解 395
26.3 Hibernate中獲取數據的策略 399
26.3.1 FetchMode.SELECT 399
26.3.2 FetchMode.JOIN 401
26.3.3 FetchMode.SUBSELECT 403
26.4 轉變解決問題的思路 405
26.5 @NamedEntityGraph和@EntityGraph使用詳解 406
26.5.1 @NamedEntityGraph和@EntityGraph的用法 407
26.5.2 @NamedEntityGraph和@EntityGraph使用實例 409
26.6 本章小結 412
第27章 SpEL在Spring中的使用方法 413
27.1 SpEL基礎 413
27.1.1 SpEL的主要語法 413
27.1.2 SpEL的基本用法 415
27.2 SpEL在Spring中的常見使用場景 416
27.2.1 @Value中的應用場景 416
27.2.2 @Query中的應用場景 422
27.2.3 @Cacheable中的應用場景 425
27.3 本章小結 427
第28章 QueryPlanCache詳解 428
28.1 一級緩存 428
28.1.1 什麼是一級緩存 428
28.1.2 一級緩存的作用 429
28.2 QueryPlanCache 432
28.2.1 QueryPlanCache是什麼 432
28.2.2 QueryPlanCache存儲的內容 433
28.2.3 QueryPlanCache和Session的關係 436
28.3 QueryPlanCache中In查詢條件引發的內存洩漏問題 438
28.3.1 In查詢條件引發內存洩漏的原因 438
28.3.2 解決In查詢條件內存洩漏的方法 440
28.4 本章小結 441
第四部分 思路擴展
第29章 二級緩存的思考:Redis與JPA如何結合 444
29.1 二級緩存的概念 444
29.1.1 Hibernate中二級緩存的配置方法 444
29.1.2 二級緩存的思考 445
29.2 利用Redis進行緩存 446
29.2.1 Spring Cache和Redis的結合 446
29.2.2 介紹Spring Cache 447
29.2.3 Spring Cache的主要註解 447
29.2.4 Spring Cache Redis的主要類 449
29.3 Spring Cache結合Redis的實踐 451
29.3.1 不同Cache name配置不同的過期時間 451
29.3.2 自定義Redis key的拼接規則 453
29.3.3 異常時不要阻礙主流程 454
29.3.4 改變默認的Cache中Redis的value序列化方式 455
29.4 本章小結 457
第30章 Spring Data Rest與JPA 458
30.1 Spring Data Rest Demo 458
30.2 Spring Data Rest的基本用法 461
30.2.1 語義化的方法 461
30.2.2 默認的狀態碼支持 462
30.2.3 分頁支持 462
30.2.4 通過@RepositoryRest-Resource改變資源的metaData 462
30.2.5 利用@RestResource改變RESTful的SearchPath 464
30.2.6 Spring Data Rest的配置項支持 465
30.3 返回結果對Jackson的支持 466
30.4 Spring Data Rest和Spring Data JPA的關係 467
30.5 本章小結 467
第31章 如何利用單元測試和集成測試讓開發效率翻倍 468
31.1 Spring Data JPA單元測試的實踐 468
31.1.1 Spring Data JPA Repository的測試用例 468
31.1.2 Repository的測試場景 470
31.2 什麼是單元測試 473
31.2.1 Service層單元測試 473
31.2.2 Controller層單元測試 475
31.3 什麼是集成測試 477
31.3.1 Service層的集成測試用例寫法 477
31.3.2 Controller層的集成測試用例寫法 478
31.3.3 集成測試的一些思考 479
31.4 JUnit 4和JUnit 5在Spring Boot中的區別 481
31.5 本章小結 482
第32章 Spring Data ElasticSearch的用法 483
32.1 Spring Data ElasticSearch入門案例 483
32.2 Spring Data ElasticSearch中的關鍵類 491
32.3 ESRepository和JPARepository同時存在 492
32.4 本章小結 495
第33章 Sharding-JDBC與JPA結合使用進行分錶 496
33.1 Sharding-JDBC簡介 496
33.2 在JPA中利用Sharding-JDBC拆表 497
33.2.1 利用JPA拆分256個表的使用案例 497
33.2.2 實際集成過程中可能產生的問題 503
33.2.3 Sharding-JDBC簡單原理分析 503
33.3 分庫的思考 505
33.3.1 垂直拆分還是水平拆分 505
33.3.2 微服務還是多數據庫 506
33.3.3 讀寫分離還是多讀多寫 506
33.3.4 分佈式事務如何處理 506
33.4 本章小結 507
結束語 師傅領進門,修行靠個人 508
作者介紹
張振華
資深Java研發工程師和架構師,在Java技術棧領域有豐富的實戰經驗,善於總結和分析問題,善於透過問題本質來解決實際工作中遇到的問題。
曾就職於驢媽媽旅遊網、上海攜程旅行網、上海要買車網等互聯網公司,有豐富的電商網站實戰經驗,就職期間擔任過資深開發人員、架構師、技術專家等,對微服務體係有很深刻的認識。
熱衷於技術探索和研發,在GitChat、拉勾教育、CSDN上分享了大量關於Spring Data JPA、Java架構底層原理的文章,並獲得一致好評。