Spring Data JPA使用入門(mén)

一.Spring Data JPA簡(jiǎn)介

Spring Data JPA 是 Spring 基于 ORM 框架傍菇、JPA 規(guī)范的基礎(chǔ)上封裝的一套 JPA 應(yīng)用框架,底層使用了 Hibernate 的 JPA 技術(shù)實(shí)現(xiàn)省艳,可使開(kāi)發(fā)者用極簡(jiǎn)的代碼即可實(shí)現(xiàn)對(duì)數(shù)據(jù)的訪(fǎng)問(wèn)和操作岭粤。它提供了包括增刪改查等在內(nèi)的常用功能接口晨抡,且易于擴(kuò)展熏瞄!學(xué)習(xí)并使用 Spring Data JPA 可以極大提高開(kāi)發(fā)效率脚祟!
由于微服務(wù)系統(tǒng)的廣泛應(yīng)用,服務(wù)粒度逐漸細(xì)化强饮,多表關(guān)聯(lián)查詢(xún)的場(chǎng)景一定程度減少。單表查詢(xún)和單表的數(shù)據(jù)操作正是JPA的優(yōu)勢(shì)为黎。我們本節(jié)就為大家介紹如何在Spring Boot中使用JPA邮丰。

二.將Spring Data JPA集成到Spring Boot

2.1 引入maven依賴(lài)包行您,包括Spring Data JPA和Mysql的驅(qū)動(dòng)

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
 <dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
</dependency>

2.2 配置數(shù)據(jù)庫(kù)連接和jpa的相關(guān)信息

spring:
  datasource:
    url: jdbc:mysql://localhost:3306/testdb?useUnicode=true&characterEncoding=utf-8&useSSL=false
    username: root
    password: root
    driver-class-name: com.mysql.jdbc.Driver
  jpa:
    database-platform: org.hibernate.dialect.MySQL5InnoDBDialect
    hibernate:
      ddl-auto: validate
    database: mysql
    show-sql: true
  • spring.jpa.database-platform=org.hibernate.dialect.MySQL5InnoDBDialect 。Hibernate 創(chuàng)建數(shù)據(jù)庫(kù)表的時(shí)候剪廉,默認(rèn)使用的數(shù)據(jù)庫(kù)存儲(chǔ)引擎是 MyISAM 娃循,這個(gè)參數(shù)作用是在建表的時(shí)候,將存儲(chǔ)引擎切換為 InnoDB 斗蒋。
  • spring.jpa.show-sql=true 在日志中打印出執(zhí)行的 SQL 語(yǔ)句信息捌斧。
  • spring.jpa.properties.hibernate.hbm2ddl.auto是hibernate的配置屬性,其主要作用是:自動(dòng)根據(jù)實(shí)體類(lèi)的定義創(chuàng)建泉沾、更新捞蚂、驗(yàn)證數(shù)據(jù)庫(kù)表結(jié)構(gòu)。所以這個(gè)參數(shù)是一個(gè)比較危險(xiǎn)的參數(shù)跷究,使用的時(shí)候一定要注意姓迅。該參數(shù)的幾種配置如下:
    • create:每次加載hibernate時(shí)都會(huì)刪除上一次的生成的表,然后根據(jù)你的model類(lèi)再重新來(lái)生成新表俊马,哪怕兩次沒(méi)有任何改變也要這樣執(zhí)行丁存,這就是導(dǎo)致數(shù)據(jù)庫(kù)表數(shù)據(jù)丟失的一個(gè)重要原因。
    • create-drop:每次加載hibernate時(shí)根據(jù)model類(lèi)生成表柴我,但是sessionFactory一關(guān)閉,表就自動(dòng)刪除解寝。
    • update:最常用的屬性,第一次加載hibernate時(shí)根據(jù)model類(lèi)會(huì)自動(dòng)建立起表的結(jié)構(gòu)(前提是先建立好數(shù)據(jù)庫(kù))艘儒,以后加載hibernate時(shí)根據(jù)model類(lèi)自動(dòng)更新表結(jié)構(gòu)聋伦,即使表結(jié)構(gòu)改變了但表中的行仍然存在不會(huì)刪除以前的行。要注意的是當(dāng)部署到服務(wù)器后彤悔,表結(jié)構(gòu)是不會(huì)被馬上建立起來(lái)的嘉抓,是要等應(yīng)用第一次運(yùn)行起來(lái)后才會(huì)。
    • validate:每次加載hibernate時(shí)晕窑,驗(yàn)證創(chuàng)建數(shù)據(jù)庫(kù)表結(jié)構(gòu)抑片,只會(huì)和數(shù)據(jù)庫(kù)中的表進(jìn)行比較,不會(huì)創(chuàng)建新表杨赤,但是會(huì)插入新值敞斋。

三.Spring Data JPA核心用法

3.1 開(kāi)發(fā)實(shí)體Model類(lèi)

@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
@Entity
@Table(name="article")
public class Article {

    @Id
    @GeneratedValue(strategy=GenerationType.IDENTITY)
    private Long id;

    @Column(nullable = false,length = 32)
    private String author;

    @Column(nullable = false, unique = true,length = 32)
    private String title;

    @Column(length = 512)
    private String content;

    private Date createTime;
}
  • @Entity 必選注解,表示這個(gè)類(lèi)是一個(gè)實(shí)體類(lèi)疾牲,接受JPA控制管理植捎,對(duì)應(yīng)數(shù)據(jù)庫(kù)中的一個(gè)表
  • @Table 可選注解,指定這個(gè)類(lèi)對(duì)應(yīng)數(shù)據(jù)庫(kù)中的表名阳柔。如果這個(gè)類(lèi)名和數(shù)據(jù)庫(kù)表名符合駝峰及下劃線(xiàn)規(guī)則焰枢,可以省略這個(gè)注解。如FlowType類(lèi)名對(duì)應(yīng)表名flow_type。
  • @Id 指定這個(gè)字段為表的主鍵
  • @GeneratedValue(strategy=GenerationType.IDENTITY) 指定主鍵的生成方式济锄,一般主鍵為自增的話(huà)暑椰,就采用GenerationType.IDENTITY的生成方式
  • @Column 注解針對(duì)一個(gè)字段,對(duì)應(yīng)表中的一列荐绝。nullable = false表示數(shù)據(jù)庫(kù)字段不能為空, unique = true表示數(shù)據(jù)庫(kù)字段不能有重復(fù)值,length = 32表示數(shù)據(jù)庫(kù)字段最大程度為32.

3.2 開(kāi)發(fā)數(shù)據(jù)操作接口

我們只需創(chuàng)建類(lèi)似XxxRepository接口繼承JpaRepository<T,ID>即可一汽,JpaRepository為我們提供了各種針對(duì)單表的數(shù)據(jù)操作方法:增刪改查、分頁(yè)低滩、排序等召夹。

public interface ArticleRepository extends JpaRepository<Article,Long> {
}

3.3 關(guān)鍵字查詢(xún)接口

除了JpaRepository為我們提供的增刪改查的方法。我們還可以自定義方法恕沫,使用起來(lái)非常簡(jiǎn)單监憎,甚至可以說(shuō)是強(qiáng)大。把下面的方法名放到ArticleRepository 里面昏兆,它就自動(dòng)為我們實(shí)現(xiàn)了通過(guò)author字段查找article表的所有數(shù)據(jù)枫虏。也就是說(shuō),我們使用了find(查找)關(guān)鍵字爬虱,JPA就自動(dòng)將方法名為我們解析成數(shù)據(jù)庫(kù)SQL操作隶债,太智能了。

public interface ArticleRepository extends JpaRepository<Article,Long> {
    //注意這個(gè)方法的名稱(chēng)跑筝,jPA會(huì)根據(jù)方法名自動(dòng)生成SQL執(zhí)行
    Article findByAuthor(String author);
}

Article findByAuthor(String author);等同于SELECT * FROM article WHERE author = ?死讹,其他具體的關(guān)鍵字,使用方法和生產(chǎn)成 SQL 如下表所示:

關(guān)鍵字 接口函數(shù)例子 JPQL 片段
And findByLastnameAndFirstname … where x.lastname = ?1 and x.firstname = ?2
Or findByLastnameOrFirstname … where x.lastname = ?1 or x.firstname = ?2
Is,Equals findByFirstnameIs,findByFirstnameEquals … where x.firstname = ?1
Between findByStartDateBetween … where x.startDate between ?1 and ?2
LessThan findByAgeLessThan … where x.age < ?1
LessThanEqual findByAgeLessThanEqual … where x.age ? ?1
GreaterThan findByAgeGreaterThan … where x.age > ?1
GreaterThanEqual findByAgeGreaterThanEqual … where x.age >= ?1
After findByStartDateAfter … where x.startDate > ?1
Before findByStartDateBefore … where x.startDate < ?1
IsNull findByAgeIsNull … where x.age is null
IsNotNull,NotNull findByAge(Is)NotNull … where x.age not null
Like findByFirstnameLike … where x.firstname like ?1
NotLike findByFirstnameNotLike … where x.firstname not like ?1
StartingWith findByFirstnameStartingWith … where x.firstname like ?1 (parameter bound with appended %)
EndingWith findByFirstnameEndingWith … where x.firstname like ?1 (parameter bound with prepended %)
Containing findByFirstnameContaining … where x.firstname like ?1 (parameter bound wrapped in %)
OrderBy findByAgeOrderByLastnameDesc … where x.age = ?1 order by x.lastname desc
Not findByLastnameNot … where x.lastname <> ?1
In findByAgeIn(Collection ages) … where x.age in ?1
NotIn findByAgeNotIn(Collection age) … where x.age not in ?1
TRUE findByActiveTrue() … where x.active = true
FALSE findByActiveFalse() … where x.active = false
IgnoreCase findByFirstnameIgnoreCase … where UPPER(x.firstame) = UPPER(?1)

可以看到我們這里沒(méi)有任何類(lèi)SQL語(yǔ)句就完成了兩個(gè)條件查詢(xún)方法曲梗。這就是Spring-data-jpa的一大特性:通過(guò)解析方法名創(chuàng)建查詢(xún)赞警。

四.SpringDataJPA實(shí)現(xiàn)分頁(yè)排序

如果一次性加載成千上萬(wàn)的列表數(shù)據(jù),在網(wǎng)頁(yè)上顯示將十分的耗時(shí)虏两,用戶(hù)體驗(yàn)不好愧旦。所以處理較大數(shù)據(jù)查詢(xún)結(jié)果展現(xiàn)的時(shí)候,分頁(yè)查詢(xún)是必不可少的定罢。分頁(yè)查詢(xún)必然伴隨著一定的排序規(guī)則笤虫,否則分頁(yè)數(shù)據(jù)的狀態(tài)很難控制,導(dǎo)致用戶(hù)可能在不同的頁(yè)看到同一條數(shù)據(jù)祖凫。本文的主要內(nèi)容就是給大家介紹一下琼蚯,如何使用Spring Data JPA進(jìn)行分頁(yè)與排序。

4.1 分頁(yè)參數(shù)Page

Pageable是Spring定義的接口惠况,用于分頁(yè)參數(shù)的傳遞遭庶,我們可以使用如下代碼進(jìn)行分頁(yè)操作:查詢(xún)第一頁(yè)(從0開(kāi)始)的數(shù)據(jù),每頁(yè)10條數(shù)據(jù)稠屠。

Pageable pageable = PageRequest.of(0, 10);   //第一頁(yè)
//Pageable pageable = PageRequest.of(1, 10);  //第二頁(yè)
//Pageable pageable = PageRequest.of(2, 10);  // 第三頁(yè)
//數(shù)據(jù)庫(kù)操作獲取查詢(xún)結(jié)果
Page<Article> articlePage = articleRepository.findAll(pageable);
//將查詢(xún)結(jié)果轉(zhuǎn)換為L(zhǎng)ist
List<Article> articleList = articlePage.getContent();

findAll方法以Page類(lèi)的對(duì)象作為響應(yīng)峦睡,如果我們想獲取查詢(xún)結(jié)果List翎苫,可以使用getContent()方法。但是不建議這樣進(jìn)行轉(zhuǎn)換赐俗,因?yàn)榍岸苏故疽粋€(gè)分頁(yè)列表拉队,不僅需要數(shù)據(jù)弊知,而且還需要一些分頁(yè)信息阻逮。如:當(dāng)前第幾頁(yè),每頁(yè)多少條秩彤,總共多少頁(yè)叔扼,總共多少條。這些信息在Page(articlePage)對(duì)象里面均可以獲取到漫雷。

4.2 排序參數(shù)Sort

Spring Data JPA提供了一個(gè)Sort對(duì)象瓜富,用以提供一種排序機(jī)制。

articleRepository.findAll(Sort.by("createTime"));

articleRepository.findAll(Sort.by("author").ascending().and(Sort.by("createTime").descending()));
  • 第一個(gè)findAll方法是按照createTime的升序進(jìn)行排序
  • 第一個(gè)findAll方法是按照author的升序排序降盹,再按照createTime的降序進(jìn)行排序
    分頁(yè)和排序在一起:
Pageable pageable = PageRequest.of(0, 10,Sort.by("createTime"));

4.3 分頁(yè)結(jié)果Slice與Page

Slice 和Page 都是Spring Data JPA的數(shù)據(jù)響應(yīng)接口与柑,其中 Page 是 Slice的子接口,它們都用于保存和返回?cái)?shù)據(jù)蓄坏。
Slice的一些重要方法:

public interface Slice<T> extends Streamable<T> {
    List <T>  getContent(); //獲取切片的內(nèi)容
    
    Pageable  getPageable(); //當(dāng)前切片的分頁(yè)信息
    
    boolean  hasContent(); //是否有查詢(xún)結(jié)果价捧?
    
    boolean  isFirst();  //是否是第一個(gè)切片
    
    boolean  isLast();  //是否是最后一個(gè)切片
    
    Pageable nextPageable(); // 下一個(gè)切片的分頁(yè)信息
    
    Pageable previousPageable(); // 上一個(gè)切片的分頁(yè)信息
}

Page的一些重要方法:

public interface Page<T> extends Slice<T> {
    //總頁(yè)數(shù)
    int getTotalPages();
    
    //總數(shù)據(jù)條數(shù)
    long getTotalElements();
}

通過(guò)這兩個(gè)接口的函數(shù)定義可以看出,Slice只關(guān)心是不是存在下一個(gè)分片(分頁(yè))涡戳,不會(huì)去數(shù)據(jù)庫(kù)count計(jì)算總條數(shù)结蟋、總頁(yè)數(shù)。所以比較適合大數(shù)據(jù)量列表的的鼠標(biāo)或手指滑屏操作渔彰,不關(guān)心總共有多少頁(yè)嵌屎,只關(guān)心有沒(méi)有下一頁(yè)。Page比較適合傳統(tǒng)應(yīng)用中的table開(kāi)發(fā)恍涂,需要知道總頁(yè)數(shù)和總條數(shù)宝惰。

五.測(cè)試JPA關(guān)鍵字查詢(xún)和分頁(yè)查詢(xún)

5.1 完善3.3節(jié)ArticleRepository接口,增加分頁(yè)查詢(xún):

public interface ArticleRepository extends JpaRepository<Article,Long> {
    //注意這個(gè)方法的名稱(chēng)再沧,jPA會(huì)根據(jù)方法名自動(dòng)生成SQL執(zhí)行
    Article findByAuthor(String author);
    
    //根據(jù)author字段查詢(xún)article表數(shù)據(jù)尼夺,傳入Pageable分頁(yè)參數(shù),不需要自己寫(xiě)SQL
    Page<Article> findByAuthor(String author, Pageable pageable);
    
}

由于JpaRepository接口繼承自PagingAndSortingRepository接口产园,所以默認(rèn)已實(shí)現(xiàn)分頁(yè)和排序查詢(xún)汞斧。

5.2編寫(xiě)并運(yùn)行測(cè)試用例

@Slf4j
@RunWith(SpringRunner.class)
@SpringBootTest
public class JPATest {

    @Resource
    private ArticleRepository articleRepository;
    
    @Test
    public void testFindByAuthor() {
        Article article = articleRepository.findByAuthor("Jerry");
        log.info(article.toString());
    }

    @Test
    public void testPageable() {
        // 查詢(xún)第一頁(yè),每頁(yè)10條數(shù)據(jù)什燕,按照createTime字段降序排列
        Pageable pageable = PageRequest.of(0, 10,Sort.by("createTime").descending());
        Page<Article> page = articleRepository.findByAuthor("William", pageable);
        for (Article article : page.getContent()) {
            log.info(article.toString());
        }
    }
}
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末粘勒,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子屎即,更是在濱河造成了極大的恐慌庙睡,老刑警劉巖事富,帶你破解...
    沈念sama閱讀 222,627評(píng)論 6 517
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異乘陪,居然都是意外死亡统台,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,180評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門(mén)啡邑,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)贱勃,“玉大人,你說(shuō)我怎么就攤上這事谤逼」笕牛” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 169,346評(píng)論 0 362
  • 文/不壞的土叔 我叫張陵流部,是天一觀(guān)的道長(zhǎng)戚绕。 經(jīng)常有香客問(wèn)我,道長(zhǎng)枝冀,這世上最難降的妖魔是什么舞丛? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 60,097評(píng)論 1 300
  • 正文 為了忘掉前任,我火速辦了婚禮果漾,結(jié)果婚禮上球切,老公的妹妹穿的比我還像新娘。我一直安慰自己跨晴,他們只是感情好欧聘,可當(dāng)我...
    茶點(diǎn)故事閱讀 69,100評(píng)論 6 398
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著端盆,像睡著了一般怀骤。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上焕妙,一...
    開(kāi)封第一講書(shū)人閱讀 52,696評(píng)論 1 312
  • 那天蒋伦,我揣著相機(jī)與錄音,去河邊找鬼焚鹊。 笑死痕届,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的末患。 我是一名探鬼主播研叫,決...
    沈念sama閱讀 41,165評(píng)論 3 422
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼璧针!你這毒婦竟也來(lái)了嚷炉?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 40,108評(píng)論 0 277
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤探橱,失蹤者是張志新(化名)和其女友劉穎申屹,沒(méi)想到半個(gè)月后绘证,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,646評(píng)論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡哗讥,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,709評(píng)論 3 342
  • 正文 我和宋清朗相戀三年嚷那,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片杆煞。...
    茶點(diǎn)故事閱讀 40,861評(píng)論 1 353
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡魏宽,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出索绪,到底是詐尸還是另有隱情湖员,我是刑警寧澤,帶...
    沈念sama閱讀 36,527評(píng)論 5 351
  • 正文 年R本政府宣布瑞驱,位于F島的核電站,受9級(jí)特大地震影響窄坦,放射性物質(zhì)發(fā)生泄漏唤反。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,196評(píng)論 3 336
  • 文/蒙蒙 一鸭津、第九天 我趴在偏房一處隱蔽的房頂上張望彤侍。 院中可真熱鬧,春花似錦逆趋、人聲如沸盏阶。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 32,698評(píng)論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)名斟。三九已至,卻和暖如春魄眉,著一層夾襖步出監(jiān)牢的瞬間砰盐,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,804評(píng)論 1 274
  • 我被黑心中介騙來(lái)泰國(guó)打工坑律, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留岩梳,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 49,287評(píng)論 3 379
  • 正文 我出身青樓晃择,卻偏偏與公主長(zhǎng)得像冀值,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子列疗,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,860評(píng)論 2 361

推薦閱讀更多精彩內(nèi)容