第十三章:SpringBoot實戰SpringDataJPA

SpringDataJPASpring Data的一個子項目,經過提供基於JPARepository極大的減小了JPA做爲數據訪問方案的代碼量,你僅僅須要編寫一個接口集成下SpringDataJPA內部定義的接口便可完成簡單的CRUD操做,理論的東西不作多解釋,下面咱們開始講解SpringBootgit

構建項目

咱們使用IntelliJ IDEA工具構建一個SpringBoot項目,預先導入Web、MySQL、JPA依賴,咱們簡單使用一個RestController來實現JPA的配置,以前也有講解JPA的簡單使用,今天詳細的講解下具體的細節性的內容,項目結構以下圖1所示:spring


圖1

使用Druid數據源

咱們使用以前章節的配置,加入Druid數據源配置到咱們的項目中,複製第四章:使用Druid做爲SpringBoot項目數據源(添加監控)項目中的application.yml配置文件到咱們項目resources下,而且修改pom.xml添加Druid數據源依賴,以下圖2所示:sql


圖2

application.yml配置文件內容以下圖3所示(具體代碼請到碼雲下載地址:git.oschina.net/jnyqy/lesso…):數據庫


圖3

使用JpaRepository

咱們在配置使用JpaRepository以前須要對應咱們的測試表添加實體映射,爲了本章的方便咱們直接使用第四章:使用Druid做爲SpringBoot項目數據源(添加監控)內的表結構以及實體,sql文件在第四章項目源碼的resource目錄下,能夠下載後自行加載到本地數據庫中,表結構以下圖4所示:tomcat


圖4

根據表結構建立對應的實體映射,簡單點,咱們使用單表操做,SpringDataJPAHibernate的語法一致內部都是使用了JPA的實現。映射實體代碼以下圖5所示:架構


圖5

上述圖5的getter/setter方法我沒有貼出來,自行工具構建就能夠了。咱們的準備作好了,下面咱們建立UserJPA接口,上圖5我已經建立到了jpa目錄內,建立完成後打開添加繼承自JpaRepositoryJpaRepository須要泛型接口參數,第一個參數是實體,第二則是主鍵的類型,UserJPA代碼以下圖6所示:app


圖6

數據訪問的接口就算是實現了,咱們繼承的JpaRepository接口內有又繼承了PagingAndSortingRepository接口以及QueryByExampleExecutor接口,這兩個接口是用來幹什麼的?而PagingAndSortingRepository接口內部又有一個繼承自CrudRepository接口。若是對架構有點了解的朋友應該都知道,這樣設計得好處。框架

CrudRepository

該接口內包含了最簡單的CRUD也就是Create、Read、Update、Delete方法,固然還有count、exists方法,以下圖7所示:less


圖7

若是自行定義的JPA繼承了該接口就會擁有CrudRepository接口內的全部方法實現。spring-boot

PagingAndSortingRepository

該接口繼承自CrudRepository接口,包含了最基本的CRUD方法的實現,該接口內部添加了兩個方法,以下圖8所示:


圖8

顧名思義,看到接口名稱就能夠聯想了,這個方法就是爲了分頁而設計的,固然不只僅是分頁還有排序方法。

QueryByExampleExecutor

咱們的JpaRepository接口繼承了該接口,這個接口提供條件查詢,複雜查詢方法,能夠經過Example方式進行查詢數據,源碼以下圖9所示:


圖9

後面咱們會講到QueryDSL,到那時你就會知道SpringDataJPA提供的複雜條件查詢並非最好的選擇。

JpaRepository

咱們自定義的接口繼承了它,也就是說咱們的UserJPA擁有了JpaRepository接口及父類接口的全部方法實現,因此咱們並不須要添加任何數據操做代碼就能夠完成數據操做,JpaRepository接口對條件查詢以及保存集合數據添加了對應的方法,代碼以下圖10所示:


圖10

具體每一個方法是用來作什麼的,根據名稱就能夠看到,這裏就不作一一的講解了。下面咱們須要測試咱們建立的UserJPA是否能夠完成咱們上述說的數據操做。

建立測試控制器

咱們直接在controller包下建立一個UserController控制器,添加@RestController註解支持,咱們由於方便這裏就不編寫Service層的代碼實現了,直接在Controller內注入UserJPA,代碼以下圖11所示:


圖11

咱們在UserController內添加了JpaRepository內部實現的findAll方法,用來查詢所有用戶數據,下面咱們啓動項目測試。

初嘗試運行測試

當你使用SpringBootApplication方式運行項目時控制檯會輸出項目運行失敗的日誌提示,這裏咱們須要註釋掉spring-boot-starter-tomcat依賴的scope屬性就能夠了。

查詢數據

嘗試訪問用戶列表地址:127.0.0.1:8080/list,能夠看到頁面輸出了一條數據,這條數據是我事先在數據庫中手動添加的,以下圖12所示:


圖12

添加數據

咱們編寫簡單的添加數據方法在UserController內,代碼以下圖13所示:


圖13

咱們在add方法內建立了一個UserEntity對象並對全部的字段都賦值。

注意:SpringDataJPA內有個save方法,這個方法不只僅是用來添加數據使用,當咱們傳入主鍵的值時則是根據主鍵的值完成更新數據操做。

咱們重啓下項目,嘗試訪問127.0.0.1:8080/add地址,界面輸出內容以下圖14所示:


圖14

界面給了咱們數據添加成功的提示,咱們訪問list地址驗證是否已經添加成功,以下圖15所示:


圖15

能夠看到,數據已經經過add方法添加到數據庫內。因爲更新的操做與添加一致這裏就不作講解了,你只須要傳入主鍵的值便可。

刪除數據

咱們簡單實現刪除一條數據,在UserController內添加delete方法,方法接受一個主鍵參數,以下圖16所示:


圖16

當咱們訪問/delete時傳入userId參數就能夠刪除對應的數據,下面咱們重啓下項目,訪問127.0.0.1:8080/delete?userId=5,界面輸入內容以下圖17所示:


圖17

數據已經成功的完成了刪除操做。

上面的操做一切都是SpringDataJPA爲咱們自動完成的,到目前爲止咱們並無編寫一句SQL,那麼SpringDataJPA是否支持自定義SQL語句呢?答案必須是確定的!由於它是這個的強大!

@Query註解自定義SQL

SpringDataJPA內部有兩種方式能夠實現自定義SQL功能,咱們先來說述使用註解的方式,後期在SpringDataJPA核心技術專題內再詳細的講解使用EntityManager是如何完成自定義SQL、調用存儲過程、視圖等等操做的。下面咱們打開UserJPA接口,添加自定義查詢年齡大於20的數據,以下圖18所示:


圖18

@Query是用來配置自定義SQL的註解,後面參數nativeQuery = true纔是代表了使用原生的sql,若是不配置,默認是false,則使用HQL查詢方式。咱們在UserController內添加方法/age,測試咱們的自定義SQL是否有效,代碼以下圖19所示:


圖19

重啓下項目,訪問127.0.0.1:8080/age,效果以下圖20所示:


圖20

@Query配合@Modifying

從名字上能夠看到咱們的@Query註解好像只是用來查詢的,可是若是配合@Modifying註解一共使用,則能夠完成數據的刪除、添加、更新操做。下面咱們來測試下自定義SQL完成刪除數據的操做,我根據名字、密碼字段共同刪除一個數據,接口代碼以下圖21所示:


圖21

咱們再來編寫UserController添加對應的方法調用deleteQuery接口方法,以下圖22所示:


圖22

重啓下項目,訪問地址:127.0.0.1:8080/deleteWhere,界面輸出內容以下圖23所示:


圖23

界面居然出現了異常,這是怎麼回事呢?能夠看到拋出的異常TranscationRequiredException,意思就是你當前的操做給你拋出了須要事務異常,SpringDataJPA自定義SQL時須要在對應的接口或者調用接口的地方添加事務註解@Transactional,來開啓事務自動化管理。下面咱們在UserJPA內添加@Transactional註解,重啓項目再來訪問剛纔的地址,效果以下圖24所示:


圖24

界面已經給我提示了刪除成功,咱們查看下控制檯看打印的SQL是不是咱們自定義的,以下圖25所示:


圖25

咱們自定義的SQL被成功的打印了,自定義SQL完成添加,更新操做時跟刪除一致,都須要添加@Query以及@Modifying註解配合使用。

自定義BaseRepository

項目在正常狀況下不只僅只繼承一個JpaRepository接口,下一章咱們整合SpringDataJPA跟QueryDSL時就須要添加多個接口繼承了,那麼咱們業務數據接口每個都去繼承幾個相同的接口?答案確定是 NO,固然多個繼承也是能夠的,不過對於系統設計還有代碼複用性來講並非最好的選擇!

咱們建立一個包名叫作base,在包內添加一個BaseRepository接口,而且接口繼承咱們的JpaRepository,代碼以下圖26所示:


圖26

又出現了一個新的註解,@NoRepositoryBean,這個註解是用來幹什麼的呢?

Spring開源程序猿在命名規則上應該是比較嚴格的,從名字上咱們幾乎就能夠判斷出用途,這個註解若是配置在繼承了JpaRepository接口以及其餘SpringDataJpa內部的接口的子接口時,子接口不被做爲一個Repository建立代理實現類。

咱們建立的業務數據接口直接繼承BaseRepository就好了,繼承的子接口會擁有JpaRepository全部方法實現。

分頁查詢

分頁對於大型系統來講確定是必不可少的,那麼咱們在SpringDataJpa內是如何使用分頁來完成查詢的呢?

通常狀況咱們會建立一個BaseEntity,在BaseEntity內添加幾個字段:排序列,排序方式,當前頁碼,每頁條數等,下面咱們也來建立這麼一個父類,代碼以下圖27所示:


圖27

咱們修改UserEntity繼承BaseEntity,而後在數據庫內添加上幾條測試數據,咱們每次頁面的數量就不用20了,咱們在建立查詢條件時修改爲2條。

咱們打開UserController添加cutPage方法,用於做爲分頁查詢入口,(注意:文章的講解都沒有添加Service層因此全部的業務邏輯都在Controller內處理的,正式項目請不要這樣編寫。)咱們在cutPage方法內添加對應的分頁邏輯,以下圖28所示:


圖28

接下來咱們重啓下項目,訪問地址:127.0.0.1:8080/cutpage?page=1,查看界面輸出效果以下圖29所示:


圖29

咱們再來看下控制檯的輸出,以下圖30所示:


圖30

能夠看到控制檯給咱們打印了兩條SQL,第一條是分頁查詢的SQL,第二條是查詢表內總數量的SQL。SpringDataJPA內部對數量作出了封裝,你能夠經過Page對象也就是PagingAndSortingRepository接口內的findAll(PageRequest request)方法的返回值類型中獲取到總條數、總頁數。

數據排序

咱們上面在BaseEntity內添加了排序的字段以及排序方式,咱們從新編輯下cutPage方法,修改pageRequest建立方式,添加Sort對象到PageRequest對象內,就能夠實現排序數據。以下圖31所示:


圖31

上圖31能夠看到咱們修改了排序字段咱們使用了默認的id,(注意:這裏的排序字段不是數據庫內的字段名而是實體內的屬性名)以及排序方式改爲了倒序,SpringDataJPA對排序方式添加了一個枚舉類型,建立Sort對象時也須要枚舉對象,由於咱們BaseEntity配置的是字符串因此上面多了一步判斷排序方式返回枚舉對象。

重啓下項目,再來訪問分頁路徑,界面輸出效果以下圖32所示:


圖32

能夠看到數據已是倒序方式展現了,控制檯的日誌輸出也對應的添加了order by語句,以下圖33所示:


圖33

總結

綜上所述本章的內容已經講解完了,本章的內容比較多昨天完成沒有編寫完,還請見諒。本章主要講解了SpringBoot項目中使用SpringDataJPA的基本操做,包括了:CURD、分頁、排序、自定義SQL、定義BaseRepository、事務處理等。本章內容並非SpringDataJPA全面內容,後續我會在SpringDataJPA核心技術專題詳細講解。

本章內容已經更新到碼雲:

SpringBoot配套源碼地址:gitee.com/hengboy/spr…

SpringCloud配套源碼地址:gitee.com/hengboy/spr…

SpringBoot相關係列文章請訪問:目錄:SpringBoot學習目錄

QueryDSL相關係列文章請訪問:QueryDSL通用查詢框架學習目錄

SpringDataJPA相關係列文章請訪問:目錄:SpringDataJPA學習目錄

SpringBoot相關文章請訪問:目錄:SpringBoot學習目錄,感謝閱讀!

歡迎加入QQ技術交流羣,共同進步。


QQ技術交流羣
相關文章
相關標籤/搜索