本書主要分為四個模組,共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
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