Like Share Discussion Bookmark Smile

J.J. Huang   2019-03-28   Spring Boot   瀏覽次數:

SpringBoot - 第十四章 | Spring-data-jpa訪問資料庫

在前面的文章中 第十三章 - SpringBoot JdbcTemplate訪問資料庫 介紹如何使用JdbcTemplate的基本訪問資料庫。

而在實際的專案開發中,最基本的資料庫操作不外乎「CRUD」,而這些操作除了資料表名稱和結構不同外,其語法都是類似的,開發人員需要寫大量類似而枯燥的語法來完成業務邏輯。

為了解決這些大量枯燥的資料操作語法,我們可以使用ORM框架,比如:Hibernate。通過整合Hibernate之後,我們以操作Java實體的方式最終將資料改變映射到資料庫表中。

為了解決抽象各個Java實體基本的「CRUD」操作,我們通常會以泛型的方式封裝一個模板Dao來進行抽像簡化,但是這樣依然不是很方便,我們需要針對每個實體編寫一個繼承自泛型模板Dao的接口,再編寫該接口的實現。雖然一些基礎的資料訪問已經可以得到很好的複用,但是在代碼結構上針對每個實體都會有一堆Dao的接口和實現。

由於模板Dao的實現,使得這些具體實體的Dao層已經變的非常”薄”,有一些具體實體的Dao實現可能完全就是對模板Dao的簡單代理,並且往往這樣的實現類可能會出現在很多實體上。 Spring-data-jpa的出現正可以讓這樣一個已經很”薄”的資料訪問層變成只是一層接口的編寫方式。

「CRUD」表示:(Create)、讀取(Read)、更新(Update)、刪除(Delete)

簡單介紹

  • JPA是Java Persistence API的簡寫,是官方提出的一種ORM規範!

  • JPA規範,都在包路徑:javax.persistence.*下,像一些常用的如:@Entity、@Id及@Transient都在此路徑下。這些也是一些現在市面上常用的ORM一些約定俗成的註解了。

  • Spring Data JPA是Spring基於Hibernate開發的一個JPA框架。可以極大的簡化JPA的寫法,可以在幾乎不用寫具體代碼的情況下,實現對資料的訪問和操作。除了「CRUD」外,還包括如分頁、排序​​等一些常用的功能。

Spring Data JPA 接口和核心概念

接口 說明
Repository 最頂層的接口,是一個空的接口,目的是為了統一所有Repository的類型,且能讓組件掃描的時候自動識別
CrudRepository 是Repository的子接口,提供CRUD的功能
PagingAndSortingRepository 是CrudRepository的子接口,添加分頁和排序的功能
JpaRepository 是PagingAndSortingRepository的子接口,增加了一些實用的功能,比如:批量操3作等
JpaSpecificationExecutor 用來做負責查詢的接口
Specification 是Spring Data JPA提供的一個查詢規範,要做複雜的查詢,只需圍繞這個規範來設置查詢條件即可

Spring Data JPA 方法命名效果

可以通過方法命名規則進行相關資料庫操作,這個確實可以減少很多代碼

關鍵字 方法命名 sql where字句
And findByNameAndPwd where name= ? and pwd =?
Or findByNameOrSex where name= ? or sex=?
Is,Equals findById,findByIdEquals where id= ?
Between findByIdBetween where id between ? and ?
LessThan findByIdLessThan where id < ?
LessThanEquals findByIdLessThanEquals where id <= ?
GreaterThan findByIdGreaterThan where id > ?
GreaterThanEquals findByIdGreaterThanEquals where id > = ?
After findByIdAfter where id > ?
Before findByIdBefore where id < ?
IsNull findByNameIsNull where name is null
isNotNull,NotNull findByNameNotNull where name is not null
Like findByNameLike where name like ?
NotLike findByNameNotLike where name not like ?
StartingWith findByNameStartingWith where name like ‘?%’
EndingWith findByNameEndingWith where name like ‘%?’
Containing findByNameContaining where name like ‘%?%’
OrderBy findByIdOrderByXDesc where id=? order by x desc
Not findByNameNot where name <> ?
In findByIdIn(Collection<?> c) where id in (?)
NotIn findByIdNotIn(Collection<?> c) where id not in (?)
True findByAaaTue where aaa = true
False findByAaaFalse where aaa = false
IgnoreCase findByNameIgnoreCase where UPPER(name)=UPPER(?)

這個方式確實減少很多程式的撰寫,但是條件一多,方法名稱就會變很長


使用範例

由於Spring-data-jpa依賴於Hibernate。如果你對Hibernate有一定了解,下面內容可以毫不費力的看懂並上手使用Spring-data-jpa。如果你還是Hibernate新手,你可以先按如下方式入門,再建議回頭學習一下Hibernate以幫助這部分的理解和進一步使用。

資料庫範例

這邊用Customer來做範例

1
2
3
4
5
6
7
8
9
10
11
DROP TABLE IF EXISTS `customer`;
CREATE TABLE `customer` (
`id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'id',
`name` varchar(64) DEFAULT NULL COMMENT '姓名',
`age` smallint(3) DEFAULT NULL COMMENT '年齡',
`create_by` varchar(50) NOT NULL COMMENT '建立人員',
`create_dt` datetime NOT NULL COMMENT '建立時間',
`modify_by` varchar(50) DEFAULT NULL COMMENT '修改人員',
`modify_dt` datetime DEFAULT NULL COMMENT '修改時間',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

相關配置

  • 加入pom的依賴

    1
    2
    3
    4
    <dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-jpa</artifactId>
    </dependency>
  • src/main/resources/application.properties中配置資料源訊息

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    # 資料源配置
    spring.datasource.url=jdbc:mysql://localhost:3306/test
    spring.datasource.username=root
    spring.datasource.password=root
    spring.datasource.driver-class-name=com.mysql.jdbc.Driver

    # 顯示SQL語法
    spring.jpa.show-sql=true
    # format SQL語法
    spring.jpa.properties.hibernate.format_sql=true

    # 顯示SQL語法的查詢條件的值
    logging.level.org.hibernate.SQL=DEBUG
    logging.level.org.hibernate.type.descriptor.sql.BasicBinder=TRACE

    # 自動建立(此參數請小心使用)
    #spring.jpa.properties.hibernate.hbm2ddl.auto=create-drop

spring.jpa.properties.hibernate.hbm2ddl.auto是hibernate的配置屬性,其主要作用是:自動建立、更新、驗證資料庫表結構。該參數的幾種配置如下:

  • create:每次加載hibernate時都會刪除上一次的生成的表,然後根據你的model類再重新來生成新表,哪怕兩次沒有任何改變也要這樣執行,這就是導致資料庫表資料丟失的一個重要原因。

  • create-drop:每次加載hibernate時根據model類生成表,但是sessionFactory一關閉,表就自動刪除。

  • update:最常用的屬性,第一次加載hibernate時根據model類會自動建立起表的結構(前提是先建立好資料庫),以後加載hibernate時根據model類自動更新表結構,即使表結構改變了但表中的行仍然存在不會刪除以前的行。要注意的是當部署到伺服器後,表結構是不會被馬上建立起來的,是要等應用第一次運行起來後才會。

  • validate:每次加載hibernate時,驗證建立資料庫表結構,只會和資料庫中的表進行比較,不會建立新表,但是會插入新值。

注意:spring.jpa.properties.hibernate.hbm2ddl.auto,於程式啟動會時自動先將你的Table Drop在自動建立與Model資料定義的欄位名稱一模一樣的Table

建立實體 (Entity)

  • 實體類上加入@EntityListeners(AuditingEntityListener.class),啟動類上加入註解@EnableJpaAuditing,這樣就實現了類似公共字段自動填充功能了@CreatedDate、@LastModifiedDate、@CreatedBy、@LastModifiedBy。

  • @Entity:告訴Spring這是資料模型層的宣告

  • @Table:Table的name對應到資料庫中的資料表名稱

  • @Id:是此資料表的Primary Key

  • @GeneratedValue:告訴此Column的生成方式。
    – GenerationType.AUTO 讓容器來自動產生
    – GenerationType.IDENTITY 讓資料庫自己維護

  • @Column:對應到Table的欄位中的欄位名稱

更多詳細資料請參考 Spring Data JPA - Reference Documentation

建立資料訪問對象 (Dao)

注意:這裡繼承了JpaRepository。另外要實現分頁功能,可以繼承PagingAndSortingRepository,佔位符為:?+具體的參數索引值;所以按自己需要做繼承選擇,CrudRepository、PagingAndSortingRepository、JpaRepository等。

編輯啟動類 (Application)

單元測試

以上三個Entity、Dao、Application處理好後,這邊就可以先進行基本的測試。

測試結果

到這邊基本上JPA的使用已經實作完畢了,而下面的部分是希望結合Service、Controller來做測試和應用,讓我們可以做個比較完整範例。
一般來說Controller多數都是處理頁面的部分,而Service就是在處理業務邏輯的部分,Dao就是單純對資料庫的操作。


建立邏輯介面層 (Service interface)

建立邏輯實作層 (Service implement)

建立Controller

Postman測試

  • 新增用戶

  • 找尋用戶(ById)

  • 刪除用戶(ById)

  • 找尋用戶(ByNameAndAge)

註:以上參考了
程序猿DD-翟永超Spring Boot中使用Spring-data-jpa让数据访问更简单、更优雅 文章。
oKongSpringBoot | 第三十章:Spring-data-jpa的集成和使用 文章。
Spring Data JPA findOne()更改为Optional如何使用这个?
Day12-Spring Boot-什麼是Spring Data JPA