Spring Boot(五):Spring Boot Jpa 的使用

在上篇文章Spring Boot(二):Web 綜合開發中簡單介紹了一下 Spring Boot Jpa 的基礎性使用,這篇文章將更加全面的介紹 Spring Boot Jpa 常見用法以及注意事項。html

使用 Spring Boot Jpa 開發時,發現國內對 Spring Boot Jpa 全面介紹的文章比較少案例也比較零碎,所以寫文章總結一下。本人也正在翻譯Spring Data JPA 參考指南,有興趣的同窗歡迎聯繫我,一塊兒加入翻譯中!java

Spring Boot Jpa 介紹

首先了解 Jpa 是什麼?

Jpa (Java Persistence API) 是 Sun 官方提出的 Java 持久化規範。它爲 Java 開發人員提供了一種對象/關聯映射工具來管理 Java 應用中的關係數據。它的出現主要是爲了簡化現有的持久化開發工做和整合 ORM 技術,結束如今 Hibernate,TopLink,JDO 等 ORM 框架各自爲營的局面。mysql

值得注意的是,Jpa是在充分吸取了現有 Hibernate,TopLink,JDO 等 ORM 框架的基礎上發展而來的,具備易於使用,伸縮性強等優勢。從目前的開發社區的反應上看,Jpa 受到了極大的支持和讚賞,其中就包括了 Spring 與 EJB3. 0的開發團隊。git

注意:Jpa 是一套規範,不是一套產品,那麼像 Hibernate,TopLink,JDO 他們是一套產品,若是說這些產品實現了這個 Jpa 規範,那麼咱們就能夠叫他們爲 Jpa 的實現產品。github

Spring Boot Jpa

Spring Boot Jpa 是 Spring 基於 ORM 框架、Jpa 規範的基礎上封裝的一套 Jpa 應用框架,可以使開發者用極簡的代碼便可實現對數據的訪問和操做。它提供了包括增刪改查等在內的經常使用功能,且易於擴展!學習並使用 Spring Data Jpa 能夠極大提升開發效率!web

Spring Boot Jpa 讓咱們解脫了 DAO 層的操做,基本上全部 CRUD 均可以依賴於它來實現spring

基本查詢

基本查詢也分爲兩種,一種是 Spring Data 默認已經實現,一種是根據查詢的方法來自動解析成 SQL。sql

預先生成方法

Spring Boot Jpa 默認預先生成了一些基本的CURD的方法,例如:增、刪、改等等數據庫

1 繼承 JpaRepositoryspringboot

public interface UserRepository extends JpaRepository<User, Long> {
}

2 使用默認方法

@Test
public void testBaseQuery() throws Exception {
    User user=new User();
    userRepository.findAll();
    userRepository.findOne(1l);
    userRepository.save(user);
    userRepository.delete(user);
    userRepository.count();
    userRepository.exists(1l);
    // ...
}

就不解釋了根據方法名就看出意思來

自定義簡單查詢

自定義的簡單查詢就是根據方法名來自動生成 SQL,主要的語法是findXXBy,readAXXBy,queryXXBy,countXXBy, getXXBy後面跟屬性名稱:

User findByUserName(String userName);

也使用一些加一些關鍵字AndOr

User findByUserNameOrEmail(String username, String email);

修改、刪除、統計也是相似語法

Long deleteById(Long id);
Long countByUserName(String userName)

基本上 SQL 體系中的關鍵詞均可以使用,例如:LIKEIgnoreCaseOrderBy

List<User> findByEmailLike(String email);
User findByUserNameIgnoreCase(String userName);
List<User> findByUserNameOrderByEmailDesc(String email);

具體的關鍵字,使用方法和生產成SQL以下表所示

Keyword Sample JPQL snippet
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)

複雜查詢

在實際的開發中咱們須要用到分頁、刪選、連表等查詢的時候就須要特殊的方法或者自定義 SQL

分頁查詢

分頁查詢在實際使用中很是廣泛了,Spring Boot Jpa 已經幫咱們實現了分頁的功能,在查詢的方法中,須要傳入參數Pageable ,當查詢中有多個參數的時候Pageable建議作爲最後一個參數傳入.

Page<User> findALL(Pageable pageable);
Page<User> findByUserName(String userName,Pageable pageable);

Pageable 是 Spring 封裝的分頁實現類,使用的時候須要傳入頁數、每頁條數和排序規則

@Test
public void testPageQuery() throws Exception {
    int page=1,size=10;
    Sort sort = new Sort(Direction.DESC, "id");
    Pageable pageable = new PageRequest(page, size, sort);
    userRepository.findALL(pageable);
    userRepository.findByUserName("testName", pageable);
}

限制查詢

有時候咱們只須要查詢前N個元素,或者支取前一個實體。

User findFirstByOrderByLastnameAsc();
User findTopByOrderByAgeDesc();
Page<User> queryFirst10ByLastname(String lastname, Pageable pageable);
List<User> findFirst10ByLastname(String lastname, Sort sort);
List<User> findTop10ByLastname(String lastname, Pageable pageable);

自定義SQL查詢

其實 Spring Data 覺大部分的 SQL 均可以根據方法名定義的方式來實現,可是因爲某些緣由咱們想使用自定義的 SQL 來查詢,Spring Data 也是完美支持的;在 SQL 的查詢方法上面使用@Query註解,如涉及到刪除和修改在須要加上@Modifying.也能夠根據須要添加 @Transactional對事物的支持,查詢超時的設置等。

@Modifying
@Query("update User u set u.userName = ?1 where u.id = ?2")
int modifyByIdAndUserId(String  userName, Long id);
    
@Transactional
@Modifying
@Query("delete from User where id = ?1")
void deleteByUserId(Long id);
  
@Transactional(timeout = 10)
@Query("select u from User u where u.emailAddress = ?1")
User findByEmailAddress(String emailAddress);

多表查詢

多表查詢 Spring Boot Jpa 中有兩種實現方式,第一種是利用 Hibernate 的級聯查詢來實現,第二種是建立一個結果集的接口來接收連表查詢後的結果,這裏主要第二種方式。

首先須要定義一個結果集的接口類。

public interface HotelSummary {

    City getCity();

    String getName();

    Double getAverageRating();

    default Integer getAverageRatingRounded() {
        return getAverageRating() == null ? null : (int) Math.round(getAverageRating());
    }

}

查詢的方法返回類型設置爲新建立的接口

@Query("select h.city as city, h.name as name, avg(r.rating) as averageRating "
        - "from Hotel h left outer join h.reviews r where h.city = ?1 group by h")
Page<HotelSummary> findByCity(City city, Pageable pageable);

@Query("select h.name as name, avg(r.rating) as averageRating "
        - "from Hotel h left outer join h.reviews r  group by h")
Page<HotelSummary> findByCity(Pageable pageable);

使用

Page<HotelSummary> hotels = this.hotelRepository.findByCity(new PageRequest(0, 10, Direction.ASC, "name"));
for(HotelSummary summay:hotels){
        System.out.println("Name" +summay.getName());
    }

在運行中 Spring 會給接口(HotelSummary)自動生產一個代理類來接收返回的結果,代碼彙總使用 getXX的形式來獲取

多數據源的支持

同源數據庫的多源支持

平常項目中由於使用的分佈式開發模式,不一樣的服務有不一樣的數據源,經常須要在一個項目中使用多個數據源,所以須要配置 Spring Boot Jpa 對多數據源的使用,通常分一下爲三步:

  • 1 配置多數據源
  • 2 不一樣源的實體類放入不一樣包路徑
  • 3 聲明不一樣的包路徑下使用不一樣的數據源、事務支持

異構數據庫多源支持

好比咱們的項目中,即須要對 mysql 的支持,也須要對 Mongodb 的查詢等。

實體類聲明@Entity 關係型數據庫支持類型、聲明@Document 爲 Mongodb 支持類型,不一樣的數據源使用不一樣的實體就能夠了

interface PersonRepository extends Repository<Person, Long> {
 …
}

@Entity
public class Person {
  …
}

interface UserRepository extends Repository<User, Long> {
 …
}

@Document
public class User {
  …
}

可是,若是 User 用戶既使用 Mysql 也使用 Mongodb 呢,也能夠作混合使用

interface JpaPersonRepository extends Repository<Person, Long> {
 …
}

interface MongoDBPersonRepository extends Repository<Person, Long> {
 …
}

@Entity
@Document
public class Person {
  …
}

也能夠經過對不一樣的包路徑進行聲明,好比 A 包路徑下使用 mysql,B 包路徑下使用 MongoDB

@EnableJpaRepositories(basePackages = "com.neo.repositories.jpa")
@EnableMongoRepositories(basePackages = "com.neo.repositories.mongo")
interface Configuration { }

其它

使用枚舉

使用枚舉的時候,咱們但願數據庫中存儲的是枚舉對應的 String 類型,而不是枚舉的索引值,須要在屬性上面添加@Enumerated(EnumType.STRING) 註解

@Enumerated(EnumType.STRING) 
@Column(nullable = true)
private UserType type;

不須要和數據庫映射的屬性

正常狀況下咱們在實體類上加入註解@Entity,就會讓實體類和表相關連若是其中某個屬性咱們不須要和數據庫來關聯只是在展現的時候作計算,只須要加上@Transient屬性既可。

@Transient
private String  userName;

源碼案例

示例代碼-github

示例代碼-碼雲

文章內容已經升級到 Spring Boot 2.x

參考

Spring Data JPA - Reference Documentation

Spring Data JPA——參考文檔 中文版

相關文章
相關標籤/搜索