欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

SpringData JPA快速上手之關(guān)聯(lián)查詢及JPQL語句書寫詳解

 更新時間:2023年09月18日 11:26:25   作者:RenX000  
JPA都有SpringBoot的官方直接提供的starter,而Mybatis沒有,直到SpringBoot 3才開始加入到官方模版中,這篇文章主要介紹了SpringData JPA快速上手,關(guān)聯(lián)查詢,JPQL語句書寫的相關(guān)知識,感興趣的朋友一起看看吧

JPA框架

image-20230915194416786

? 在我們之前編寫的項目中,我們不難發(fā)現(xiàn),實際上大部分的數(shù)據(jù)庫交互操作,到最后都只會做一個事情,那就是把數(shù)據(jù)庫中的數(shù)據(jù)映射為Java中的對象。比如我們要通過用戶名去查找對應(yīng)的用戶,或是通過ID查找對應(yīng)的學(xué)生信息,在使用Mybatis時,我們只需要編寫正確的SQL語句就可以直接將獲取的數(shù)據(jù)映射為對應(yīng)的Java對象,通過調(diào)用Mapper中的方法就能直接獲得實體類,這樣就方便我們在Java中數(shù)據(jù)庫表中的相關(guān)信息了。

? 但是以上這些操作都有一個共性,那就是它們都是通過某種條件去進行查詢,而最后的查詢結(jié)果,都是一個實體類,所以你會發(fā)現(xiàn)你寫的很多SQL語句都是一個套路 select * from xxx where xxx=xxx ,實際上對于這種簡單SQL語句,我們完全可以弄成一個模版來使用,那么能否有一種框架,幫我們把這些相同的套路給封裝起來,直接把這類相似的SQL語句給屏蔽掉,不再由我們編寫,而是讓框架自己去組合拼接。

認識SpringData JPA

首先我們來看一個國外的統(tǒng)計:

image-20230306224859664

在國外JPA幾乎占據(jù)了主導(dǎo)地位,而Mybatis并不像國內(nèi)那樣受待見,所以你會發(fā)現(xiàn),JPA都有SpringBoot的官方直接提供的starter,而Mybatis沒有,直到SpringBoot 3才開始加入到官方模版中。

那么,什么是JPA:

JPA(Java Persistence API)和JDBC類似,也是官方定義的一組接口,但是它相比傳統(tǒng)的JDBC,它是為了實現(xiàn)ORM而生的,即Object-Relationl Mapping,它的作用是在關(guān)系型數(shù)據(jù)庫和對象之間形成一個映射,這樣,我們在具體的操作數(shù)據(jù)庫的時候,就不需要再去和復(fù)雜的SQL語句打交道,只要像平時操作對象一樣操作它就可以了。

其中比較常見的JPA實現(xiàn)有:

  • Hibernate:Hibernate是JPA規(guī)范的一個具體實現(xiàn),也是目前使用最廣泛的JPA實現(xiàn)框架之一。它提供了強大的對象關(guān)系映射功能,可以將Java對象映射到數(shù)據(jù)庫表中,并提供了豐富的查詢語言和緩存機制。
  • EclipseLink:EclipseLink是另一個流行的JPA實現(xiàn)框架,由Eclipse基金會開發(fā)和維護。它提供了豐富的特性,如對象關(guān)系映射、緩存、查詢語言和連接池管理等,并具有較高的性能和可擴展性。
  • OpenJPA:OpenJPA是Apache基金會的一個開源項目,也是JPA規(guī)范的一個實現(xiàn)。它提供了高性能的JPA實現(xiàn)和豐富的特性,如延遲加載、緩存和分布式事務(wù)等。
  • TopLink:TopLink是Oracle公司開發(fā)的一個對象關(guān)系映射框架,也是JPA規(guī)范的一個實現(xiàn)。雖然EclipseLink已經(jīng)取代了TopLink成為Oracle推薦的JPA實現(xiàn),但TopLink仍然得到廣泛使用。

JPA:具體的實現(xiàn)交給框架,我們只需要一一對應(yīng)自己設(shè)置的實體類就行,方便很多

而實現(xiàn)JPA規(guī)范的框架一般最常用的就是 Hibernate ,它是一個重量級框架,學(xué)習(xí)難度相比Mybatis也更高一些,而SpringDataJPA也是采用Hibernate框架作為底層實現(xiàn),并對其加以封裝。

官網(wǎng):https://spring.io/projects/spring-data-jpa

使用JPA快速上手

同樣的,我們只需要導(dǎo)入stater依賴即可:

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

接著我們可以直接創(chuàng)建一個類,比如用戶類,只需要把一個賬號對應(yīng)的屬性全部定義好即可:

@Data
public class Account {
    int id;
    String username;
    String password;
}

通過注解形式在屬性上添加數(shù)據(jù)庫映射關(guān)系,這樣就能夠讓JPA知道我們的實體類對應(yīng)的數(shù)據(jù)庫表長啥樣,這里用到了很多注解:

@Data
@Entity   //表示這個類是一個實體類
@Table(name = "account")    //對應(yīng)的數(shù)據(jù)庫中表名稱
public class Account {
    @GeneratedValue(strategy = GenerationType.IDENTITY)   //生成策略,這里配置為自增
    @Column(name = "id")    //對應(yīng)表中id這一列
    @Id     //此屬性為主鍵
    int id;
    @Column(name = "username")   //對應(yīng)表中username這一列
    String username;
    @Column(name = "password")   //對應(yīng)表中password這一列
    String password;
}

接著修改配置文件,把日志打印給打開:

spring:
  jpa:
    #開啟SQL語句執(zhí)行日志信息
    show-sql: true
    hibernate:
      #配置為檢查數(shù)據(jù)庫表結(jié)構(gòu),沒有時會自動創(chuàng)建
      ddl-auto: update

ddl-auto 屬性用于設(shè)置自動表定義,可以實現(xiàn)自動在數(shù)據(jù)庫中為我們創(chuàng)建一個表,表的結(jié)構(gòu)會根據(jù)我們定義的實體類決定,它有以下幾種:

  • none : 不執(zhí)行任何操作,數(shù)據(jù)庫表結(jié)構(gòu)需要手動創(chuàng)建。
  • create : 框架在每次運行時都會刪除所有表,并重新創(chuàng)建。
  • create-drop : 框架在每次運行時都會刪除所有表,然后再創(chuàng)建,但在程序結(jié)束時會再次刪除所有表。
  • update : 框架會檢查數(shù)據(jù)庫表結(jié)構(gòu),如果與實體類定義不匹配,則會做相應(yīng)的修改,以保持它們的一致性。
  • validate : 框架會檢查數(shù)據(jù)庫表結(jié)構(gòu)與實體類定義是否匹配,如果不匹配,則會拋出異常。

這個配置項的作用是為了避免手動管理數(shù)據(jù)庫表結(jié)構(gòu),使開發(fā)者可以更方便地進行開發(fā)和測試,但在生產(chǎn)環(huán)境中,更推薦使用數(shù)據(jù)庫遷移工具來管理表結(jié)構(gòu)的變更。

我們可以在日志中發(fā)現(xiàn),在啟動時執(zhí)行了如下SQL語句:

image-20230915201350981

我們的數(shù)據(jù)庫中對應(yīng)的表已經(jīng)自動創(chuàng)建好了

接著來看如何訪問表,需要創(chuàng)建一個Repository實現(xiàn)類:

@Repository
public interface AccountRepository extends JpaRepository<Account, Integer> {
}

注意JpaRepository有兩個泛型,前者是具體操作的對象實體,也就是對應(yīng)的表,后者是ID的類型,接口中已經(jīng)定義了比較常用的數(shù)據(jù)庫操作。編寫接口繼承即可,可以直接注入此接口獲得實現(xiàn)類:

@Resource
AccountRepository repository;
@Test
void contextLoads() {
    Account account = new Account();
    account.setUsername("小紅");
    account.setPassword("1234567");
    System.out.println(repository.save(account).getId());   //使用save來快速插入數(shù)據(jù),并且會返回插入的對象,如果存在自增ID,對象的自增id屬性會自動被賦值,這就很方便了
}

執(zhí)行結(jié)果如下:

image-20230915201527776

同時,查詢操作也很方便:

@Test
void contextLoads() {
  	//默認通過通過ID查找的方法,并且返回的結(jié)果是Optional包裝的對象,非常人性化
    repository.findById(1).ifPresent(System.out::println);
}

得到結(jié)果為:

image-20230915195547388

包括常見的一些計數(shù)、刪除操作等都包含在里面,僅僅配置應(yīng)該接口就能完美實現(xiàn)增刪改查:

image-20230721000050875

我們發(fā)現(xiàn),使用了JPA之后,整個項目的代碼中沒有出現(xiàn)任何的SQL語句,可以說是非常方便了,JPA依靠我們提供的注解信息自動完成了所有信息的映射和關(guān)聯(lián)。

相比Mybatis,JPA幾乎就是一個全自動的ORM框架,而Mybatis則頂多算是半自動ORM框架。

方法名稱拼接自定義SQL

雖然接口預(yù)置的方法使用起來非常方便,但是如果我們需要進行條件查詢等操作或是一些判斷,就需要自定義一些方法來實現(xiàn),同樣的,我們不需要編寫SQL語句,而是通過方法名稱的拼接來實現(xiàn)條件判斷,這里列出了所有支持的條件判斷名稱:

屬性拼接方法名稱示例執(zhí)行的語句
DistinctfindDistinctByLastnameAndFirstnameselect distinct … where x.lastname = ?1 and x.firstname = ?2
AndfindByLastnameAndFirstname… where x.lastname = ?1 and x.firstname = ?2
OrfindByLastnameOrFirstname… where x.lastname = ?1 or x.firstname = ?2
Is,EqualsfindByFirstname , findByFirstnameIs , findByFirstnameEquals… where x.firstname = ?1
BetweenfindByStartDateBetween… where x.startDate between ?1 and ?2
LessThanfindByAgeLessThan… where x.age < ?1
LessThanEqualfindByAgeLessThanEqual… where x.age <= ?1
GreaterThanfindByAgeGreaterThan… where x.age > ?1
GreaterThanEqualfindByAgeGreaterThanEqual… where x.age >= ?1
AfterfindByStartDateAfter… where x.startDate > ?1
BeforefindByStartDateBefore… where x.startDate < ?1
IsNull,NullfindByAge(Is)Null… where x.age is null
IsNotNull,NotNullfindByAge(Is)NotNull… where x.age not null
LikefindByFirstnameLike… where x.firstname like ?1
NotLikefindByFirstnameNotLike… where x.firstname not like ?1
StartingWithfindByFirstnameStartingWith… where x.firstname like ?1(參數(shù)與附加 % 綁定)
EndingWithfindByFirstnameEndingWith… where x.firstname like ?1(參數(shù)與前綴 % 綁定)
ContainingfindByFirstnameContaining… where x.firstname like ?1(參數(shù)綁定以 % 包裝)
OrderByfindByAgeOrderByLastnameDesc… where x.age = ?1 order by x.lastname desc
NotfindByLastnameNot… where x.lastname <> ?1
InfindByAgeIn(Collection ages)… where x.age in ?1
NotInfindByAgeNotIn(Collection ages)… where x.age not in ?1
TruefindByActiveTrue… where x.active = true
FalsefindByActiveFalse… where x.active = false
IgnoreCasefindByFirstnameIgnoreCase… where UPPER(x.firstname) = UPPER(?1)

比如我們想要實現(xiàn)根據(jù)用戶名模糊匹配查找用戶:

@Repository
public interface AccountRepository extends JpaRepository<Account, Integer> {
    //按照表中的規(guī)則進行名稱拼接,不用刻意去記,IDEA會有提示
    List<Account> findAllByUsernameLike(String str);
}

測試一下:

@Test
void contextLoads() {
    repository.findAllByUsernameLike("%明%").forEach(System.out::println);
}

image-20230721001035279

同時根據(jù)用戶名和ID一起查詢:

@Repository
public interface AccountRepository extends JpaRepository<Account, Integer> {
    List<Account> findAllByUsernameLike(String str);
    Account findByIdAndUsername(int id, String username);
    //也可以使用Optional類進行包裝,Optional<Account> findByIdAndUsername(int id, String username);
}
@Test
void contextLoads() {
    System.out.println(repository.findByIdAndUsername(1, "小明"));
}

想判斷數(shù)據(jù)庫中是否存在某個ID的用戶:

@Repository
public interface AccountRepository extends JpaRepository<Account, Integer> {
    List<Account> findAllByUsernameLike(String str);
    Account findByIdAndUsername(int id, String username);
    //使用exists判斷是否存在
    boolean existsAccountById(int id);
}

注意自定義條件操作的方法名稱一定要遵循規(guī)則,不然會出現(xiàn)異常:

Caused by: org.springframework.data.repository.query.QueryCreationException: Could not create query for public abstract  ...

有了這些操作,我們在編寫一些簡單SQL的時候就很方便了,用久了甚至直接忘記SQL怎么寫。

關(guān)聯(lián)查詢

在實際開發(fā)中,比較常見的場景還有關(guān)聯(lián)查詢,也就是我們會在表中添加一個外鍵字段,而此外鍵字段又指向了另一個表中的數(shù)據(jù),當(dāng)我們查詢數(shù)據(jù)時,可能會需要將關(guān)聯(lián)數(shù)據(jù)也一并獲取,比如我們想要查詢某個用戶的詳細信息,一般用戶簡略信息會單獨存放一個表,而用戶詳細信息會單獨存放在另一個表中。當(dāng)然,除了用戶詳細信息之外,可能在某些電商平臺還會有用戶的購買記錄、用戶的購物車,交流社區(qū)中的用戶帖子、用戶評論等,這些都是需要根據(jù)用戶信息進行關(guān)聯(lián)查詢的內(nèi)容。

在JPA中,每張表實際上就是一個實體類的映射,而表之間的關(guān)聯(lián)關(guān)系,也可以看作對象之間的依賴關(guān)系,比如用戶表中包含了用戶詳細信息的ID字段作為外鍵,那么實際上就是用戶表實體中包括了用戶詳細信息實體對象:

@Data
@Entity
@Table(name = "users_detail")
public class AccountDetail {
    @Column(name = "id")
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Id
    int id;
    @Column(name = "address")
    String address;
    @Column(name = "email")
    String email;
    @Column(name = "phone")
    String phone;
    @Column(name = "real_name")
    String realName;
}

而用戶信息和用戶詳細信息之間形成了一對一的關(guān)系,那么這時直接在類中指定這種關(guān)系:

@Data
@Entity
@Table(name = "users")
public class Account {
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "id")
    @Id
    int id;
    @Column(name = "username")
    String username;
    @Column(name = "password")
    String password;
    @JoinColumn(name = "detail_id")   //指定存儲外鍵的字段名稱
    @OneToOne    //聲明為一對一關(guān)系
    AccountDetail detail;
}

在修改實體類信息后,我們發(fā)現(xiàn)在啟動時也進行了更新,日志如下:

image-20230915202053963

接著往用戶詳細信息中添加一些數(shù)據(jù),一會可以直接進行查詢:

@Test
void pageAccount() {
    repository.findById(1).ifPresent(System.out::println);
}

查詢后,可以發(fā)現(xiàn),得到如下結(jié)果:

image-20230915202154380

也就是,在建立關(guān)系之后,我們查詢Account對象時,會自動將關(guān)聯(lián)數(shù)據(jù)的結(jié)果也一并進行查詢。

那要是我們只想要Account的數(shù)據(jù),不想要用戶詳細信息數(shù)據(jù)怎么辦呢?我希望在我要用的時候再獲取詳細信息,這樣可以節(jié)省一些網(wǎng)絡(luò)開銷,我們可以設(shè)置懶加載,這樣只有在需要時才會向數(shù)據(jù)庫獲取:

@JoinColumn(name = "detail_id")
@OneToOne(fetch = FetchType.LAZY)    //將獲取類型改為LAZY
AccountDetail detail;

接著測試一下:

@Transactional   //懶加載屬性需要在事務(wù)環(huán)境下獲取,因為repository方法調(diào)用完后Session會立即關(guān)閉
@Test
void pageAccount() {
    repository.findById(1).ifPresent(account -> {
        System.out.println(account.getUsername());   //獲取用戶名
        System.out.println(account.getDetail());  //獲取詳細信息(懶加載)
    });
}

接著來看看控制臺輸出了什么:

Hibernate: select account0_.id as id1_0_0_, account0_.detail_id as detail_i4_0_0_, account0_.password as password2_0_0_, account0_.username as username3_0_0_ from users account0_ where account0_.id=?
Test
Hibernate: select accountdet0_.id as id1_1_0_, accountdet0_.address as address2_1_0_, accountdet0_.email as email3_1_0_, accountdet0_.phone as phone4_1_0_, accountdet0_.real_name as real_nam5_1_0_ from users_detail accountdet0_ where accountdet0_.id=?
AccountDetail(id=1, address=四川省成都市青羊區(qū), email=8371289@qq.com, phone=1234567890, realName=盧本)

可以看到,獲取用戶名之前,并沒有去查詢用戶的詳細信息,而是當(dāng)我們獲取詳細信息時才進行查詢并返回AccountDetail對象。

也可以在添加數(shù)據(jù)時,利用實體類之間的關(guān)聯(lián)信息,一次性添加兩張表的數(shù)據(jù):需要稍微修改一下級聯(lián)關(guān)聯(lián)操作設(shè)定:

@JoinColumn(name = "detail_id")
@OneToOne(fetch = FetchType.LAZY, cascade = CascadeType.ALL) //設(shè)置關(guān)聯(lián)操作為ALL
AccountDetail detail;
  • ALL:所有操作都進行關(guān)聯(lián)操作
  • PERSIST:插入操作時才進行關(guān)聯(lián)操作
  • REMOVE:刪除操作時才進行關(guān)聯(lián)操作
  • MERGE:修改操作時才進行關(guān)聯(lián)操作

可以多個并存,接著進行一下測試:

@Test
void addAccount(){
    Account account = new Account();
    account.setUsername("Nike");
    account.setPassword("123456");
    AccountDetail detail = new AccountDetail();
    detail.setAddress("重慶市渝中區(qū)解放碑");
    detail.setPhone("1234567890");
    detail.setEmail("73281937@qq.com");
    detail.setRealName("張三");
  	account.setDetail(detail);
    account = repository.save(account);
    System.out.println("插入時,自動生成的主鍵ID為:"+account.getId()+",外鍵ID為:"+account.getDetail().getId());
}

可以看到日志結(jié)果:

Hibernate: insert into users_detail (address, email, phone, real_name) values (?, ?, ?, ?)
Hibernate: insert into users (detail_id, password, username) values (?, ?, ?)
插入時,自動生成的主鍵ID為:6,外鍵ID為:3

結(jié)束后會發(fā)現(xiàn)數(shù)據(jù)庫中兩張表都同時存在數(shù)據(jù)。

接著我們來看一對多關(guān)聯(lián),比如每個用戶的成績信息:

@JoinColumn(name = "uid")  //注意這里的name指的是Score表中的uid字段對應(yīng)的就是當(dāng)前的主鍵,會將uid外鍵設(shè)置為當(dāng)前的主鍵
@OneToMany(fetch = FetchType.LAZY, cascade = CascadeType.REMOVE)   //在移除Account時,一并移除所有的成績信息,依然使用懶加載
List<Score> scoreList;
@Data
@Entity
@Table(name = "users_score")   //成績表,注意只存成績,不存學(xué)科信息,學(xué)科信息id做外鍵
public class Score {
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "id")
    @Id
    int id;
    @OneToOne   //一對一對應(yīng)到學(xué)科上
    @JoinColumn(name = "cid")
    Subject subject;
    @Column(name = "socre")
    double score;
    @Column(name = "uid")
    int uid;
}
@Data
@Entity
@Table(name = "subjects")   //學(xué)科信息表
public class Subject {
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "cid")
    @Id
    int cid;
    @Column(name = "name")
    String name;
    @Column(name = "teacher")
    String teacher;
    @Column(name = "time")
    int time;
}

在數(shù)據(jù)庫中填寫相應(yīng)數(shù)據(jù),接著我們就可以查詢用戶的成績信息了:

@Transactional
@Test
void test() {
    repository.findById(1).ifPresent(account -> {
        account.getScoreList().forEach(System.out::println);
    });
}

成功得到用戶所有的成績信息,包括得分和學(xué)科信息。

同樣的,我們還可以將對應(yīng)成績中的教師信息單獨分出一張表存儲,并建立多對一的關(guān)系,因為多門課程可能由同一個老師教授(千萬別搞暈了,一定要理清楚關(guān)聯(lián)關(guān)系,同時也是考驗?zāi)愕幕A(chǔ)扎不扎實):

@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "tid")   //存儲教師ID的字段,和一對一是一樣的,也會當(dāng)前表中創(chuàng)個外鍵
Teacher teacher;

接著就是教師實體類了:

@Data
@Entity
@Table(name = "teachers")
public class Teacher {
    @Column(name = "id")
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Id
    int id;
    @Column(name = "name")
    String name;
    @Column(name = "sex")
    String sex;
}

最后我們再進行一下測試:

@Transactional
@Test
void test() {
    repository.findById(3).ifPresent(account -> {
        account.getScoreList().forEach(score -> {
            System.out.println("課程名稱:"+score.getSubject().getName());
            System.out.println("得分:"+score.getScore());
            System.out.println("任課教師:"+score.getSubject().getTeacher().getName());
        });
    });
}

成功得到多對一的教師信息。

最后我們再來看最復(fù)雜的情況,現(xiàn)在我們一門課程可以由多個老師教授,而一個老師也可以教授多個課程,那么這種情況就是很明顯的多對多場景,現(xiàn)在又該如何定義呢?我們可以像之前一樣,插入一張中間表表示教授關(guān)系,這個表中專門存儲哪個老師教哪個科目:

@ManyToMany(fetch = FetchType.LAZY)   //多對多場景
@JoinTable(name = "teach_relation",     //多對多中間關(guān)聯(lián)表
        joinColumns = @JoinColumn(name = "cid"),    //當(dāng)前實體主鍵在關(guān)聯(lián)表中的字段名稱
        inverseJoinColumns = @JoinColumn(name = "tid")   //教師實體主鍵在關(guān)聯(lián)表中的字段名稱
)
List<Teacher> teacher;

接著,JPA會自動創(chuàng)建一張中間表,并自動設(shè)置外鍵,我們就可以將多對多關(guān)聯(lián)信息編寫在其中了。

JPQL自定義SQL語句

雖然SpringDataJPA能夠簡化大部分數(shù)據(jù)獲取場景,但是難免會有一些特殊的場景,需要使用復(fù)雜查詢才能夠去完成,這時你又會發(fā)現(xiàn),如果要實現(xiàn),只能用回Mybatis了,因為我們需要自己手動編寫SQL語句,過度依賴SpringDataJPA會使得SQL語句不可控。

使用JPA,我們也可以像Mybatis那樣,直接編寫SQL語句,不過它是JPQL語言,與原生SQL語句很類似,但是它是面向?qū)ο蟮?,?dāng)然我們也可以編寫原生SQL語句。

比如我們要更新用戶表中指定ID用戶的密碼:

@Repository
public interface AccountRepository extends JpaRepository<Account, Integer> {
    @Transactional    //DML操作需要事務(wù)環(huán)境,可以不在這里聲明,但是調(diào)用時一定要處于事務(wù)環(huán)境下
    @Modifying     //表示這是一個DML操作
    @Query("update Account set password = ?2 where id = ?1") //這里操作的是一個實體類對應(yīng)的表,參數(shù)使用?代表,后面接第n個參數(shù)
    int updatePasswordById(int id, String newPassword);
}
@Test
void updateAccount(){
    repository.updatePasswordById(1, "654321");
}

現(xiàn)在我想使用原生SQL來實現(xiàn)根據(jù)用戶名稱修改密碼:

@Transactional
@Modifying
@Query(value = "update users set password = :pwd where username = :name", nativeQuery = true) //使用原生SQL,和Mybatis一樣,這里使用 :名稱 表示參數(shù),當(dāng)然也可以繼續(xù)用上面那種方式。
int updatePasswordByUsername(@Param("name") String username,   //我們可以使用@Param指定名稱
                             @Param("pwd") String newPassword);
@Test
void updateAccount(){
    repository.updatePasswordByUsername("Admin", "654321");
}

通過編寫原生SQL,在一定程度上彌補了SQL不可控的問題。

雖然JPA能夠為我們帶來非常便捷的開發(fā)體驗,但是正是因為太便捷了,尤其是一些國內(nèi)用到復(fù)雜查詢業(yè)務(wù)的項目,可能開發(fā)到后期特別龐大時,就只能從底層SQL語句開始進行優(yōu)化,而由于JPA盡可能地在屏蔽我們對SQL語句的編寫,所以后期優(yōu)化是個大問題,并且Hibernate相對于Mybatis來說,更加重量級。不過,在微服務(wù)的時代,單體項目一般不會太大,JPA的劣勢并沒有太明顯地體現(xiàn)出來。

到此這篇關(guān)于SpringData JPA快速上手,關(guān)聯(lián)查詢,JPQL語句書寫的文章就介紹到這了,更多相關(guān)SpringData JPA關(guān)聯(lián)查詢內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • 教你代碼中獲取當(dāng)前?JAR?包的存放位置

    教你代碼中獲取當(dāng)前?JAR?包的存放位置

    這篇文章主要介紹了如何獲取當(dāng)前JAR包的存放位置,要獲取當(dāng)前運行的 JAR 包所存放的位置,可以使用 ProtectionDomain 和 CodeSource 類,本文結(jié)合實例代碼給大家介紹的非常詳細,需要的朋友可以參考下
    2023-08-08
  • 詳解JAVA Timer和TimerTask

    詳解JAVA Timer和TimerTask

    這篇文章主要介紹了JAVA Timer和TimerTask的相關(guān)資料,文中講解非常細致,代碼幫助大家更好的理解和學(xué)習(xí),感興趣的朋友可以了解下
    2020-07-07
  • @Schedule?如何解決定時任務(wù)推遲執(zhí)行

    @Schedule?如何解決定時任務(wù)推遲執(zhí)行

    這篇文章主要介紹了@Schedule?如何解決定時任務(wù)推遲執(zhí)行問題。具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-09-09
  • SpringBoot3使用?自定義注解+Jackson實現(xiàn)接口數(shù)據(jù)脫敏的步驟

    SpringBoot3使用?自定義注解+Jackson實現(xiàn)接口數(shù)據(jù)脫敏的步驟

    本文介紹了一種以優(yōu)雅的方式實現(xiàn)對接口返回的敏感數(shù)據(jù),如手機號、郵箱、身份證等信息的脫敏處理,這種方法也是企業(yè)常用方法,話不多說我們一起來看一下吧
    2024-03-03
  • Spring中實現(xiàn)的三種異步流式接口方法

    Spring中實現(xiàn)的三種異步流式接口方法

    在現(xiàn)代Web開發(fā)中,接口超時是一個常見的問題,尤其是在處理耗時操作時,傳統(tǒng)的同步接口在處理長時間任務(wù)時會阻塞請求線程,從而影響系統(tǒng)的響應(yīng)能力,本文將詳細講解Spring中實現(xiàn)的三種異步流式接口方法,需要的朋友可以參考下
    2024-10-10
  • Spring Security實現(xiàn)微信公眾號網(wǎng)頁授權(quán)功能

    Spring Security實現(xiàn)微信公眾號網(wǎng)頁授權(quán)功能

    這篇文章主要介紹了Spring Security中實現(xiàn)微信網(wǎng)頁授權(quán),本文通過實例代碼給大家介紹的非常詳細,對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2021-08-08
  • Maven項目打包為jar的四種方式

    Maven項目打包為jar的四種方式

    本文主要介紹了Maven項目打包為jar的四種方式,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2024-10-10
  • 我對@RestController注解的理解

    我對@RestController注解的理解

    這篇文章主要介紹了我對@RestController注解的理解,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2024-03-03
  • MyBatis之傳入?yún)?shù)為list、數(shù)組、map的寫法

    MyBatis之傳入?yún)?shù)為list、數(shù)組、map的寫法

    這篇文章主要介紹了MyBatis之傳入?yún)?shù)為list、數(shù)組、map的寫法,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2023-11-11
  • 使用Spring靜態(tài)注入實現(xiàn)讀取配置工具類新方式

    使用Spring靜態(tài)注入實現(xiàn)讀取配置工具類新方式

    這篇文章主要介紹了使用Spring靜態(tài)注入實現(xiàn)讀取配置工具類新方式,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-02-02

最新評論