Spring Boot 2.0 讀書筆記_09:Spring Data JPA 上

6. Spring Data JPA 上

JPA

經過上篇文章從封裝角度上對數據庫操作的敘述,很好的爲下文JPA操作做了鋪墊。

這個地方需要注意的是 Spring Data JPA 不是一個名詞,Spring DataJPA兩個的集成哦!

Spring Data JPA,在JPA提供的簡單語義上做了一定程度的封裝,滿足基本CURD的操作需求。此外,Spring Data爲Spring框架對訪問SQL和NoSQL數據庫提供了一致的方式。

Spring Data:數據庫交互的方式

關鍵字:Spring官方提供一套數據層綜合解決方案

Spring Data 是爲數據訪問提供熟悉且一致的基於Spring的編程模型,同時仍保留底層數據存儲的特殊特性。在關係數據庫和非關係數據庫,map-reduce框架以及基於雲的數據服務變得很容易。旨在統一和簡化對各類型持久化存儲和訪問,使得對數據庫的訪問變得方便快捷。

JPA:Java持久層API(Java Persistence API)

關鍵字:ORM規範

JPA本質是一種ORM規範(爲JPA並未提供ORM實現,只是制定了規範)。只是提供了一些相關的接口,但是接口並不能直接使用,需要實現容器。

Hibernate 從3.2開始,就開始兼容JPA。Hibernate3.2獲得了Sun TCK的 JPA(Java Persistence API) 兼容認證。

JPA和Hibernate之間的關係,可以簡單的理解爲JPA是標準接口,Hibernate是實現,並不是一對一關係。Hibernate屬於遵循JPA規範的一種實現,但是JPA是Hibernate遵循的規範之一,Hibernate還有其他實現的規範。
在這裏插入圖片描述
簡單來講就是:ORM框架的實現遵循包括JPA(ORM規範)在內的多個規範。反過來講,JPA(ORM規範)同樣適用於多種ORM框架。


而本章的主角:Spring Data JPA 便是Spring官方所給出的一種數據庫訪問操作的解決方案。

Spring Data JPA, part of the larger Spring Data family, makes it easy to easily implement JPA based repositories. This module deals with enhanced support for JPA based data access layers. It makes it easier to build Spring-powered applications that use data access technologies.
Implementing a data access layer of an application has been cumbersome for quite a while. Too much boilerplate code has to be written to execute simple queries as well as perform pagination, and auditing. Spring Data JPA aims to significantly improve the implementation of data access layers by reducing the effort to the amount that’s actually needed. As a developer you write your repository interfaces, including custom finder methods, and Spring will provide the implementation automatically.

官方說明中表明:Spring Data JPA會使得基於數據庫的JPA規範更加的簡單高效。

上面也提到了JPA採取了Hibernate的框架層面的實現,那麼這裏的JPA(ORM規範)的數據庫封裝角度也是基於Java Entity的。

雖然上述的說明有些拗口,但是我們可以認爲Spring Data JPASpring官方所給出的一種ORM框架


廢話不多說,開整!

Spring Boot 集成 Spring Data JPA,添加依賴即可開始我們的Spring Data JPA之旅。

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

前期配置:
配置文件:application.properties

  spring.datasource.url=jdbc:mysql://127.0.0.1:3306/orm?useUnicode=true&characterEncoding=UTF-8
  spring.datasource.username=root
  spring.datasource.password=1234
  spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
  spring.jpa.show-sql =true

配置類:DataSourceConfig.java,連接池方面採用了Hikari

@Configuration
public class DataSourceConfig {

    @Bean(name = "dataSource")
    public DataSource datasource(Environment env) {
        HikariDataSource ds = new HikariDataSource();
        ds.setJdbcUrl(env.getProperty("spring.datasource.url"));
        ds.setUsername(env.getProperty("spring.datasource.username"));
        ds.setPassword(env.getProperty("spring.datasource.password"));
        ds.setDriverClassName(env.getProperty("spring.datasource.driver-class-name"));
        return ds;
    }
}

配置JPA支持:Spring Data JPA 採用了 Hibernate 實現,需要關注兩個特性

  1. spring.jpa.hibernate.ddl-auto:是否自動建庫。默認爲none,Hibernate 能根據 Entity的定義自動生成表以及修改己有的表和表主鍵設置等。
  2. spring.jpa.show-sql:是否打印SQL。默認爲false,這裏我們設置爲true,我們需要看到數據庫操作的SQL語句。

Java Entity配置(不同於常用的POJO類)

封裝角度從Java Entity出發的JPA,自然對Java Entity的配置是很嚴格了!
JPA提供了很多註解進行配置Java Entity,這裏列舉下常用的註解類型並給出例子。

@Entity
public class User  {

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

  // 部門
  @Column
  private String name;

  // 創建時間
  @Column(name="create_time")
  private Date createTime ;
  
  // 部門
  @ManyToOne
  @JoinColumn(name="department_id")
  Department department;

  public User() {
    // 默認無參構造函數必須有
  }

  // getter and setter func etc..
}
註解 說明 備註
@Entity 實體POJO類必須使用的標識註解
@Id 聲明該成員屬性映射到數據庫表的主鍵字段
@GeneratedValue 數據庫主鍵生成策略 IDENTITY:採用數據庫ID自增長的方式來自增主鍵字段,Oracle 不支持這種方式。
AUTO: JPA自動選擇合適的策略,是默認選項。
SEQUENCE:通過序列產生主鍵,通過@SequenceGenerator 註解指定序列名,MySql不支持這種方式。
TABLE:通過表產生主鍵,框架藉由表模擬序列產生主鍵,使用該策略可以使應用更易於數據庫移植。
@Column 表明成員屬性與數據庫表字段對應 name屬性可指定字段名(適用於屬性與字段名不一致情況)
@ManyToOne Many 指的是該定義成員變量的實體,即User實體。
One 指的是該註解所註解的成員屬性,即Department實體。
ManyToOne 說明對象 User 和 Department 的冠以是多對一的關係。即,多個用戶屬於一個部門。
@OneToMany 反之同理
@JoinColumn 與@ManyToOne結合使用,說明外鍵字段是department_id

@OneToMany舉例:

@Entity
punlic class Department {
  
  @OneToMany(mappedBy="department")
  private Set<User> users = new HashSet<User>();

  public Department () {}

  // getter and setter func etc..
}

Department實體中存在一個users成員變量,且類型是Set[表示集合元素無序]。@OneToMany註解表明一個部門具有多個用戶。這裏還需要注意:在一對多的關係映射上,One端採用@OneToMany註解時必須使用mapperBy屬性聲明Many端的對象[User]的department屬性提供了對應的關係映射。

上述是完整的Java Entity 配置項,當然現在的越來越多的JPA應用採用了簡化的Entity定義,去掉了關係映射的相關配置和數據庫外鍵的相關配置。

Repository

RepositorySpring Data 的核心概念,抽象了對數據庫和NoSQL的操作。提供了幾個常用接口供我們使用:

  • Repository: 最頂層的接口,是一個空接口,目的是爲了統一所有的Repository的類型,且能讓組件掃描時自動識別。
  • CrudRepository:提供了基本的CURD,批量操作接口。
  • PagingAndSortingRepository:集成CrudRepository,提供分頁排序等功能。
  • JpaRepository:JPA專用,提供更多豐富的數據庫訪問接口。

那它們的之間的關係如圖:接口間的的逐級繼承
在這裏插入圖片描述
這裏還提到了Spring Data操作數據庫和NoSQL庫NoSQL庫主要包括:Redis、MongoDB、Elasticsearch。

在Spring官網上可以看到這些項目的介紹和使用如圖:
在這裏插入圖片描述
接下來分別對常用接口進行說明:

  • CrudRepository:實現Entity的基本CURD操作功能。

    @org.springframework.data.repository.NoRepositoryBean
    public interface CrudRepository <T, ID> extends org.springframework.data.repository.Repository<T,ID> {
        
      // save 保存 entity,如果Entity包含主鍵,則認爲是更新操作
      <S extends T> S save(S s);
    
      <S extends T> java.lang.Iterable<S> saveAll(java.lang.Iterable<S> iterable);
    
      // findById 根據主鍵查詢實體 返回Optional對象        
      java.util.Optional<T> findById(ID id);
    
      // existsById 根據主鍵返回對象是否存在
      boolean existsById(ID id);
    
      java.lang.Iterable<T> findAll();
    
      java.lang.Iterable<T> findAllById(java.lang.Iterable<ID> iterable);
    
      // 返回Entity個數
      long count();
    
      // deleteById 根據主鍵刪除Entity
      void deleteById(ID id);
    
      // 刪除實體
      void delete(T t);
    
      void deleteAll(java.lang.Iterable<? extends T> iterable);
      // 刪除全部實體
      void deleteAll();
    }
    

    T表示實體類,ID表示主鍵封裝類,ID必須實現序列化接口。類似DAO接口和XML映射文件的關係。

    public interface UserRepository extends CrudRepository<User, Integer> { }
    
  • PagingAndSortingRepository:增加了分頁和排序相關的操作功能。

    @org.springframework.data.repository.NoRepositoryBean
    public interface PagingAndSortingRepository <T, ID> 
        extends org.springframework.data.repository.CrudRepository<T,ID> {
        
      // 按照 Sort 指定的排序返回所有實體
      java.lang.Iterable<T> findAll(org.springframework.data.domain.Sort sort);
      
      // Pageable 構造了查詢的翻頁參數,Page 表示了查詢的具體結果。[查詢結果集相關數據]
      org.springframework.data.domain.Page<T> findAll(org.springframework.data.domain.Pageable pageable);
    }
    
  • JpaRepository:提供了更多使用的功能,以及通過Example對象進行查詢。

    @NoRepositoryBean
    public interface JpaRepository<T, ID> 
            extends PagingAndSortingRepository<T, ID>, QueryByExampleExecutor<T> {
    
      // 保存或更新一組實體
      <S extends T> List<S> saveAll(Iterable<S> entities);
    
      // 批量刪除一組實體
      void deleteInBatch(Iterable<T> entities);
    
      // 查詢滿足 example 條件的所有對象
      <S extends T> List<S> findAll(Example<S> example);
    
      // 查詢滿足 example 條件的所有對象,並按照 Sort 對象的排序規則進行排序。
      <S extends T> List<S> findAll(Example<S> example, Sort sort);
    }
    
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章