Spring Boot數(shù)據(jù)庫交互之Spring Data JPA

Spring Data JPA介紹
Spring Boot中支持的數(shù)據(jù)庫交互方式多種多樣,今天咱就來玩一下Spring Data JPA好了葫录,因為其他的阀湿,咱也還不會呀8鲜臁?陷嘴!

JPA全稱為Java Persistence API(Java持久層API)映砖,它是Sun公司在JavaEE 5中提出的Java持久化規(guī)范。它為Java開發(fā)人員提供了一種對象/關(guān)聯(lián)映射工具灾挨,來管理Java應(yīng)用中的關(guān)系數(shù)據(jù)邑退,JPA吸取了目前Java持久化技術(shù)的優(yōu)點,旨在規(guī)范劳澄、簡化Java對象的持久化工作地技。很多ORM框架都是實現(xiàn)了JPA的規(guī)范,如:Hibernate浴骂、EclipseLink乓土。

Spring Data JPA旨在通過減少實際需要的工作量來顯著改善數(shù)據(jù)訪問層的實現(xiàn)。它在JPA的基礎(chǔ)上做了一些封裝溯警,可以輕松實現(xiàn)基于JPA的存儲庫趣苏。 此模塊處理對基于JPA的數(shù)據(jù)訪問層的增強支持。 它使構(gòu)建使用數(shù)據(jù)訪問技術(shù)的Spring驅(qū)動應(yīng)用程序變得更加容易梯轻。

需要注意的是JPA統(tǒng)一了Java應(yīng)用程序訪問ORM框架的規(guī)范

JPA為我們提供了以下規(guī)范:

  1. ORM映射元數(shù)據(jù):JPA支持XML和注解兩種元數(shù)據(jù)的形式食磕,元數(shù)據(jù)描述對象和表之間的映射關(guān)系,框架據(jù)此將實體對象持久化到數(shù)據(jù)庫表中喳挑;
  2. JPA 的API:用來操作實體對象彬伦,執(zhí)行CRUD操作,框架在后臺替我們完成所有的事情伊诵,開發(fā)人員不用再寫SQL了(只能說在一定程度上不用寫SQL单绑,實際情況可能還是會用一些SQL);
  3. JPQL查詢語言:通過面向?qū)ο蠖敲嫦驍?shù)據(jù)庫的查詢語言查詢數(shù)據(jù)曹宴,避免程序的SQL語句緊密耦合搂橙;

以上的定義引用自網(wǎng)絡(luò)技術(shù)文章,我還在不斷理解與學(xué)習(xí)中笛坦,我們先來Demo一個例子:

P.S.:本演示是基于上期文章創(chuàng)建的項目演進的:

5分鐘入手Spring Boot

集成Spring Data JPA
以連接Oracle為例(網(wǎng)上有很多Mysql的案例区转,除了配置不一樣,其實使用差不多版扩,有機會我們可以Demo Mysql废离、Mongo的案例)
在項目pom.xml中的dependencies節(jié)點加入以下依賴:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
    <groupId>com.oracle</groupId>
    <artifactId>ojdbc8</artifactId>
    <version>12.2.0.1.0</version>
</dependency>

準(zhǔn)備數(shù)據(jù)庫配置

  1. 在src/main底下創(chuàng)建resources文件夾;

  2. 在resources文件夾內(nèi)新建application.properties文件礁芦;


    resources
  3. 在application.properties文件內(nèi)輸入數(shù)據(jù)庫的配置信息蜻韭,如:

spring.datasource.url=jdbc:oracle:thin:@//xxdb-scan:xxxx/XXXX
spring.datasource.username=xxxx
spring.datasource.password=xxxxxxxx
spring.datasource.driver-class-name=oracle.jdbc.OracleDriver
spring.jpa.show-sql=true
spring.jackson.serialization.indent_output=true
  1. 啟動項目,驗證數(shù)據(jù)庫配置正確與否;


    啟動項目 1

    啟動項目 2

創(chuàng)建實體類entity
假設(shè)我們的數(shù)據(jù)庫中有個表叫LEAD表(也叫l(wèi)ead表)湘捎,我們想查詢LEAD表中的數(shù)據(jù)诀豁;

  1. 創(chuàng)建entity包;
  2. 在entity包內(nèi)創(chuàng)建實體類Lead.java;


    實體類
  3. 編寫實體類窥妇;
    (LEAD 表有多個字段舷胜,我們本例只使用其中的2個字段,一個是lead_id, 一個是email;)
package com.mycompany.sample.entity;

import javax.persistence.*;

/**
 * @author : dylanz
 * @since : 06/30/2020
 **/
@Entity
@Table(name = "LEAD")
public class Lead {
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    @Column(name = "lead_id")
    private int leadId;
    @Column(name = "email")
    private String email;

    public Lead() {
    }

    public Lead(Integer leadId, String email) {
        this.leadId = leadId;
        this.email = email;
    }

    public int getLeadId() {
        return leadId;
    }

    public void setLeadId(int leadId) {
        this.leadId = leadId;
    }

    public String getEmail() {
        return email;
    }

    public void setEmail(String email) {
        this.email = email;
    }
}
#@Table(name = "LEAD")這個非必需活翩,當(dāng)未提供時烹骨,說明本實體類的表名是實體類類名轉(zhuǎn)換后的名字,如:
# 1.實體類名為Lead時材泄,默認(rèn)表名為:lead表沮焕;
# 2.實體類名為UserPermission時,默認(rèn)表名為:user_permission表拉宗;
#@Column(name = "lead_id")中name為非必需峦树,當(dāng)未提供時,說明數(shù)據(jù)庫的列名為對應(yīng)成員變量轉(zhuǎn)換后的名字旦事,如:
# 1.當(dāng)對應(yīng)的成員變量為private int leadId; 時魁巩,默認(rèn)數(shù)據(jù)庫列名為lead_id;
# 2.當(dāng)對應(yīng)的成員變量為private int email; 時,默認(rèn)數(shù)據(jù)庫列名為email;
#可以看到姐浮,實體類和成員變量均為駝峰結(jié)構(gòu)谷遂,而對應(yīng)的表明和數(shù)據(jù)庫列名為下劃線結(jié)構(gòu);
#盡管如此卖鲤,還是建議補全@Table和@Column肾扰;
#Spring Boot還有很多注解和屬性,可以用于規(guī)范實體類及實體類的列蛋逾,比如長度限制集晚、數(shù)據(jù)類型限制等,
#這里不再詳細(xì)介紹区匣,畢竟我們本例的重點不是介紹這個甩恼。

創(chuàng)建repository
有了實體類之后,我們接下來要創(chuàng)建一個repository接口類沉颂,并在repository接口類內(nèi)實現(xiàn)數(shù)據(jù)庫交互,并且把交互結(jié)果映射到實體類Lead.java

  1. 創(chuàng)建repository包悦污;
  2. 在repository包內(nèi)創(chuàng)建repository接口類LeadRepository.java铸屉;


    repository接口類
  3. 編寫repository接口類;
package com.mycompany.sample.repository;

import com.mycompany.sample.entity.Lead;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Modifying;
import org.springframework.data.jpa.repository.Query;
import org.springframework.stereotype.Repository;

import javax.transaction.Transactional;

/**
 * @author : dylanz
 * @since : 06/30/2020
 **/
@Repository
public interface LeadRepository extends JpaRepository<Lead, Integer> {
    @Query(value = "select l from Lead l where leadId=?1")
    Lead getLeadByLeadId(Integer leadId);

    @Query(value = "select lead_id,email from lead where lead_id=?1", nativeQuery = true)
    Lead getLeadByLeadIdWithNativeQuery(Integer leadId);

    @Modifying
    @Query(value = "update lead set email=?1 where lead_id=?2", nativeQuery = true)
    @Transactional
    void updateLeadEmail(String email, Integer leadId);
}
#增切端、刪彻坛、改的數(shù)據(jù)庫交互,必須搭配@Modifying使用,并且建議也使用注解@Transactional來處理事務(wù)昌屉,
#即交互失敗钙蒙,Spring Boot會自動幫我們進行回滾。

創(chuàng)建service
repository創(chuàng)建完之后间驮,我們就可以與數(shù)據(jù)庫進行交互了躬厌,接下來我們寫個service調(diào)用repository

  1. 創(chuàng)建service包;
  2. 創(chuàng)建service類竞帽;


    service類
  3. 編寫service類扛施;
package com.mycompany.sample.service;

import com.mycompany.sample.entity.Lead;
import com.mycompany.sample.repository.LeadRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

/**
 * @author : dylanz
 * @since : 06/30/2020
 **/
@Service
public class LeadService {
    @Autowired
    private LeadRepository leadRepository;

    public Lead getLead(Integer leadId) {
        return leadRepository.getLeadByLeadId(leadId);
    }

    public Lead getLeadByLeadIdWithNativeQuery(Integer leadId) {
        return leadRepository.getLeadByLeadIdWithNativeQuery(leadId);
    }

    public Lead updateEmail(com.mycompany.sample.domain.Lead lead) {
        int leadId = lead.getLeadId();
        String email = lead.getEmail();
        leadRepository.updateLeadEmail(email, leadId);
        Lead updatedLead = leadRepository.getLeadByLeadId(leadId);

        if (updatedLead.getEmail() != null && !updatedLead.getEmail().equals(email)) {
            throw new InternalError("Unable to update email for leadId: " + leadId + " with email: " + email);
        }
        return updatedLead;
    }
}

開發(fā)帶數(shù)據(jù)庫交互功能的API
service開發(fā)完成后,我們要把該service暴露給客戶端使用屹篓,于是就要創(chuàng)建API了

  1. 創(chuàng)建Controller疙渣;


    Controller
  2. 編寫Controller;
package com.mycompany.sample.controller;

import com.mycompany.sample.entity.Lead;
import com.mycompany.sample.service.LeadService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

/**
 * @author : dylanz
 * @since : 06/30/2020
 **/
@RestController
public class LeadController {
    @Autowired
    private LeadService leadService;

    @GetMapping("/getLead/{leadId}")
    @ResponseBody
    public Lead getLead(@PathVariable Integer leadId) {
        return leadService.getLead(leadId);
    }

    @GetMapping("/getLead")
    @ResponseBody
    public Lead getLeadById(@RequestParam("leadId") Integer leadId) {
        return leadService.getLeadByLeadIdWithNativeQuery(leadId);
    }

    @PutMapping(value = "/updateLeadEmail")
    @ResponseBody
    public Lead updateLeadEmail(@RequestBody com.mycompany.sample.domain.Lead lead) {
        return leadService.updateEmail(lead);
    }
}
  1. 為了演示PUT請求堆巧,我還建了個updateLeadEmail API妄荔,并且引入lombok;
  • pom.xml中dependencies節(jié)點內(nèi)添加lombok依賴
<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
    <version>1.18.12</version>
    <scope>provided</scope>
</dependency>
  • 建立domain包谍肤;
  • 編寫Lead domain;
package com.mycompany.sample.domain;

import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import lombok.Data;

import java.io.Serializable;

/**
 * @author : dylanz
 * @since : 06/30/2020
 **/
@Data
@JsonIgnoreProperties(ignoreUnknown = true)
public class Lead implements Serializable {
    private static final long serialVersionUID = 1L;

    private Integer leadId;
    private String email;
}

運行Spring Boot項目啦租,見證奇跡

調(diào)用Get API,返回執(zhí)行結(jié)果:

http://127.0.0.1:8080/getLead?leadId=10xxxx46http://127.0.0.1:8080/getLead/10xxxx46

API交互結(jié)果 1

API交互結(jié)果 2

調(diào)用Put API谣沸,返回執(zhí)行結(jié)果:

API交互結(jié)果 3
  1. 同時項目log中刷钢,我們可以找到被執(zhí)行的sql:
    為了能看到sql,關(guān)鍵一步是src/main/resources/application.properties內(nèi)的配置項:spring.jpa.show-sql=true
    后臺log

其中第一條SQL是非nativeQuery的乳附,第二内地、三條SQL是nativeQuery的,nativeQuery的SQL就是我們平常寫的sql赋除,而非nativeQuery的SQL阱缓,是Spring Boot JPA幫我們生成的。

到此為止举农,我們已經(jīng)完成了Spring Boot項目中采用Spring Boot JPA方式與數(shù)據(jù)庫交互的實現(xiàn)荆针!

碼字不容易,點贊需積極

謝謝0湓恪:奖场!

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末棱貌,一起剝皮案震驚了整個濱河市玖媚,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌婚脱,老刑警劉巖今魔,帶你破解...
    沈念sama閱讀 212,454評論 6 493
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件勺像,死亡現(xiàn)場離奇詭異,居然都是意外死亡错森,警方通過查閱死者的電腦和手機吟宦,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,553評論 3 385
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來涩维,“玉大人殃姓,你說我怎么就攤上這事〖づ玻” “怎么了辰狡?”我有些...
    開封第一講書人閱讀 157,921評論 0 348
  • 文/不壞的土叔 我叫張陵,是天一觀的道長垄分。 經(jīng)常有香客問我宛篇,道長,這世上最難降的妖魔是什么薄湿? 我笑而不...
    開封第一講書人閱讀 56,648評論 1 284
  • 正文 為了忘掉前任叫倍,我火速辦了婚禮,結(jié)果婚禮上豺瘤,老公的妹妹穿的比我還像新娘吆倦。我一直安慰自己,他們只是感情好坐求,可當(dāng)我...
    茶點故事閱讀 65,770評論 6 386
  • 文/花漫 我一把揭開白布蚕泽。 她就那樣靜靜地躺著,像睡著了一般桥嗤。 火紅的嫁衣襯著肌膚如雪须妻。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,950評論 1 291
  • 那天泛领,我揣著相機與錄音荒吏,去河邊找鬼。 笑死渊鞋,一個胖子當(dāng)著我的面吹牛绰更,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播锡宋,決...
    沈念sama閱讀 39,090評論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼儡湾,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了执俩?” 一聲冷哼從身側(cè)響起徐钠,我...
    開封第一講書人閱讀 37,817評論 0 268
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎奠滑,沒想到半個月后丹皱,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,275評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡宋税,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,592評論 2 327
  • 正文 我和宋清朗相戀三年摊崭,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片杰赛。...
    茶點故事閱讀 38,724評論 1 341
  • 序言:一個原本活蹦亂跳的男人離奇死亡呢簸,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出乏屯,到底是詐尸還是另有隱情根时,我是刑警寧澤,帶...
    沈念sama閱讀 34,409評論 4 333
  • 正文 年R本政府宣布辰晕,位于F島的核電站蛤迎,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏含友。R本人自食惡果不足惜替裆,卻給世界環(huán)境...
    茶點故事閱讀 40,052評論 3 316
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望窘问。 院中可真熱鬧辆童,春花似錦、人聲如沸惠赫。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,815評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽儿咱。三九已至庭砍,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間概疆,已是汗流浹背逗威。 一陣腳步聲響...
    開封第一講書人閱讀 32,043評論 1 266
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留岔冀,地道東北人凯旭。 一個月前我還...
    沈念sama閱讀 46,503評論 2 361
  • 正文 我出身青樓,卻偏偏與公主長得像使套,于是被迫代替她去往敵國和親罐呼。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 43,627評論 2 350