Spring Boot之Spring-Data-JPA

前言: 之前總結了 Spring Boot 入門相關的博文,後端開發自然離不開對數據庫的操作,所以今天來對數據庫操作進行總結。由於剛入門,選擇一種使用簡單的組件——Jpa。簡單到我們不需要寫一句 sql 語句。

下面引用官網對 Spring-Data-Jpa 的介紹:

Spring Data JPA 是 Spring Data 系列的一部分,可以輕鬆實現基於 JPA 的存儲庫。 該模塊處理對基於 JPA 的數據訪問層的增強的支持。 這使得使用數據訪問技術構建Spring 的應用程序變得更加容易。

如果我們使用原生 JDBC 的方式來訪問數據庫,那麼我們必須編寫太多的樣板代碼。開發效率明顯降低,Jpa 則定義了對象關係映射以及實體對象持久化的標準接口,也就是 ORM 框架,相信做過 Java /android 的 oop 編程的人都或多或少的接觸過,以面向對象的方式來操作數據庫,Spring Data JPA 則在基於 JPA 進一步簡化了數據訪問層的實現,它提供了一種類似於聲明式編程的方式,開發者只需要編寫數據訪問接口(稱爲Repository),Spring Data JPA 就能基於接口中的方法命名自動地生成實現。

廢話就到這了,注意正式開始使用之前,本地必須裝有數據庫,以及對數據庫基本操作有一定的瞭解,這裏我使用的是 MySql 數據庫,安裝過程請自行 google ,使用可以參考鏈接:mysql基本操作命令彙總--筆記

一、 首先添加依賴

 

        <dependency>
            <!--下載所有Spring Data Jpa所需的依賴-->
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-jpa</artifactId>
        </dependency>

        <dependency>
            <!--我們的數據庫是mysql,所以還需要mysql-connector-java依賴-->
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </dependency>

二、數據源配置

在配置文件 application.properties 中添加配置

 

spring.jpa.show-sql = true
spring.jpa.hibernate.ddl-auto=update

spring.datasource.url=jdbc:mysql://localhost:3306/db_users
spring.datasource.username=root//配置數據庫賬號
spring.datasource.password=root//配置數據庫密碼
spring.datasource.driver-class-name=com.mysql.jdbc.Driver//配置MySql驅動

配置解析:

  • spring.datasource.url:配置本地數據庫訪問地址,默認端口3306,數據庫名:db_users
  • spring.jpa.show-sql:設置爲 true,當我們操作數據庫時,會在控制檯顯示出我們操作對應的 sql 語句,false 則不行。
  • spring.jpa.hibernate.ddl-auto:設置爲 update,當我們更新數據庫的時候,不會刪除舊錶,如果使用 create,更新數據庫時,會刪除舊錶重建,會造成數據丟失。

就這樣配置就可以操作數據庫了,當然還有更多的配置可以參考下官方文檔,我們只需要關注 以spring.datasourcespring.jpa 開頭的即可。

三、創建數據表

前面我們說了 Jpa 是 orm 映射型框架。只要我們聲明實體類,實體類中的字段就會映射到數據庫中自動生成數據表。
新建 User 類:

 

@Entity//自動映射數據表
public class User {
    //id自增
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long id;
    @Column
    private String username;
    @Column
    private String password;
    public User() {
    }
    public User(String username, String password) {
        this.username = username;
        this.password = password;
    }
.......此處省略set get方法
}

分析:User 類包含三個字段:

  • id作爲唯一標識符,@GeneratedValue(strategy=GenerationType.AUTO)表明id是一個自增字段。
  • usernamepassword 爲普通字段,@Column註解可有可無
  • @Entity註解:標記在類上,當程序運行,User 類會自動映射到數據庫中,生成以User 名的數據表,User 類的字段自動映射爲數據表的字段。
  • @Table(name = {數據表名}):可有可無,如果我們不喜歡默認用類名作爲數據表名,可以使用註解自定義數據表名

運行項目,此時不出意外,服務器啓動成功會自動生成```user``數據表

數據表.png

命令行查看,user 數據表已經創建成功~

四、數據表增刪改查操作

前面我們提到 Spring-Data-Jpa 提供了一種類似於聲明式編程的方式,開發者只需要編寫數據訪問接口(稱爲Repository),Spring Data JPA就能基於接口中的方法命名自動地生成實現。

定義 UserRepository 接口,繼承JpaRepository,此接口是 Spring-Data-Jpa 內部定義好的泛型接口,第一個參數實體類,第二個參數是ID。已經幫我們實現了基本的增刪改查的功能,現在只要持有 UserRepository 就能操作數據表,哈哈~就是如此神奇。。

 

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

源碼分析:進入源碼查看接口的繼承結構發現 JpaRepository繼承自PagingAndSortingRepository繼承自CrudRepository繼承自Repository

  • Repository:泛型接口,第一個參數是實體類,第二個參數是實體類ID,最頂層接口,不包含任何方法,目的是爲了統一所有的 Repository 的類型,且能讓組件掃描的時候自動識別。

 

public interface Repository<T, ID extends Serializable> {
}
  • CrudRepositoryRepository的子接口,封裝數據表的 CRUD 方法。

 

public interface CrudRepository<T, ID extends Serializable> extends Repository<T, ID> {
    <S extends T> S save(S var1);//存儲一條數據實體

    <S extends T> Iterable<S> save(Iterable<S> var1);//批量存儲數據

    T findOne(ID var1);//根據id查詢一條數據實體

    boolean exists(ID var1);//判斷指定id是否存在

    Iterable<T> findAll();//查詢所有的數據

    Iterable<T> findAll(Iterable<ID> var1);//根據一組id批量查詢實體

    long count();//返回數據的條數

    void delete(ID var1);//根據id刪除數據

    void delete(T var1);//刪除數據

    void delete(Iterable<? extends T> var1);//批量刪除數據

    void deleteAll();//刪除所有數據
}
  • PagingAndSortingRepository: CrudRepository的子接口,擴展了分頁和排序功能。

 

public interface PagingAndSortingRepository<T, ID extends Serializable> extends CrudRepository<T, ID> {
    Iterable<T> findAll(Sort var1);//根據某個排序獲取所有數據
    Page<T> findAll(Pageable var1);//根據分頁信息獲取某一頁的數據
}
  • JpaRepository: PagingAndSortingRepository的子接口,增加一些實用的功能, 如批量操作

 

public interface JpaRepository<T, ID extends Serializable> extends PagingAndSortingRepository<T, ID> {
    List<T> findAll(); //獲取所有數據,以List的方式返回

    List<T> findAll(Sort var1); //根據某個排序獲取所有數據,以List的方式返回

    List<T> findAll(Iterable<ID> var1); //根據一組id返回對應的對象,以List的方式返回

    <S extends T> List<S> save(Iterable<S> var1); //將一組對象持久化到數據庫中,以List的方式返回

    void flush(); //將修改更新到數據庫

    <S extends T> S saveAndFlush(S var1); //保存數據並將修改更新到數據庫

    void deleteInBatch(Iterable<T> var1); //批量刪除數據

    void deleteAllInBatch(); //批量刪除所有數據

    T getOne(ID var1); //根據id查找並返回一個對象
}

五、實際應用

定義完接口之後,只要拿到接口引用,我們就能輕鬆完成基本的數據表操作了,現在來試試寫幾個 url 接口玩玩,體驗一下。寫接口之前建議先看下文章 Spring Boot 學習總結之 Controller 註解

  • UserRepository 引用注入UserController,編寫 POST 請求的 url 接口,提交一條表單數據保存到數據表中。

 

@RestController//處理http請求,返回json格式
@RequestMapping(value = "/users")//配置url,讓該類下的所有接口url都映射在/users下
public class UserController {

    @Autowired//注入實例
    UserRepository userRepository;

    @PostMapping(value = "/save")
    public User saveUser(@RequestParam(value = "username", required = false, defaultValue = "張少林") String username,
                         @RequestParam(value = "password", required = false, defaultValue = "123456") String password) {
        User user = new User(username, password);
        return userRepository.save(user);//保存數據到數據表中,並返回
    }
}

此時 url 接口地址可以爲:http://127.0.0.1:8080/users/save?username=張少林&password=123456,請求方法:post,結果在界面上顯示 json 格式數據:

插入數據.png

 

查看數據表 數據已經存入成功:

插入一條數據.png

  • 我們手動往數據表中添加三條數據,測試一下 查詢方法
    編寫查詢所有用戶數據 url 接口

 

    @GetMapping(value = "/all")
    public List<User> findAll() {
        return userRepository.findAll();//查詢所有數據並返回
    }

url 接口地址:http://127.0.0.1:8080/users/all 請求方法 :GET,結果如下

 

查詢所有數據.png


注意:實體類 User 必須添加空構造方法,否則這裏查詢會報錯
其他的方法就不一一舉例了,按照上面源碼中的方法依葫蘆畫瓢就能操作數據表了。那麼問題來了,Jpa 內部只幫我們實現了簡單的 Crud方法,那麼遇到較爲複雜自定義條件查詢操作咋辦呢?,這時候就要用到 Spring-Data 的內建查詢機制了。

 

六、內建查詢機制

Spring Data 會識別出find...By, read...Byget...By這樣的前綴,從後面的命名中解析出查詢的條件。方法命名的的第一個By表示查詢條件的開始,多個條件可以通過AndOr來連接。

舉個栗子哈.jpg

UserRepository 中聲明查詢方法:

 

public interface UserRepository extends JpaRepository<User, Long> {
    /**
     * \根據用戶名批量查詢用戶數據
     *
     * @param username
     * @return
     */
    List<User> findByUsername(String username);

}

就是如此簡單,只需要在接口中聲明對應的查詢方法,不需要去實現它,Spring-Data-Jpa 會根據方法名幫我們智能解析爲 sql 語句,並且執行查詢。

測試:數據庫中再手動添加兩條相同用戶數據,編寫 url 請求接口

 

    @GetMapping(value = "/findByUsername")
    public List<User> findByUsername(@RequestParam(value = "username", required = false,
            defaultValue = "張少林") String username) {
        return userRepository.findByUsername(username);//根據用戶名批量查詢用戶數據
    }

配置 url 地址 返回結果爲:

根據用戶名查詢.png

可以看到控制檯打印了 sql 語句:

sql語句.png

這也印證了我們之前的觀點, Spring-Data-Jpa 自動根據方法名智能幫我們解析 sql 語句並執行查詢功能。

除了AndOr,表示查詢條件的屬性表達式中還可以通過BetweenLessThanGreaterThanLike等操作符。 可以使用IngoreCase來忽略屬性的大小寫,也可以使用AllIgnoreCase來忽略全部屬性的大小寫。

可以使用OrderBy來進行排序查詢,排序的方向是AscDesc

Spring-Data 爲我們提供的關鍵字見下面表格:

關鍵字 例子 對應的JPQL語句
And findByLastnameAndFirstname … where x.lastname = ?1 and x.firstname = ?2
Or findByLastnameOrFirstname … where x.lastname = ?1 or x.firstname = ?2
Is,Equals findByFirstname,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)

結語:至此,Spring-Data-Jpa 的基本使用總結先告一段落了,雖然還有很多東西沒涉及到,但是基於此,再結合 Spring Boot 學習總結之 Controller 註解 我們寫簡單的後臺 json 數據接口已經沒啥問題了。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章