1. 程式人生 > >Spring-Data-JPA嘗鮮:快速搭建CRUD+分頁後臺實例

Spring-Data-JPA嘗鮮:快速搭建CRUD+分頁後臺實例

第一次運行 應付 代碼 簡單的 interface sql face 語句 rom

技術分享圖片

前言:由於之前沒有接觸過Hibernate框架,但是最近看一些博客深深被它的“效率”所吸引,所以這就來跟大家一起就著一個簡單的例子來嘗嘗Spring全家桶裏自帶的JPA的鮮

Spring-DATA-JPA 簡介

JPA(Java Persistence API)是Sun官方提出的Java持久化規範。它為Java開發人員提供了一種對象/關聯映射工具來管理Java應用中的關系數據。他的出現主要是為了簡化現有的持久化開發工作和整合ORM技術,結束現在Hibernate,TopLink,JDO等ORM框架各自為營的局面。值得註意的是,JPA是在充分吸收了現有Hibernate,TopLink,JDO等ORM框架的基礎上發展而來的,具有易於使用,伸縮性強等優點。從目前的開發社區的反應上看,JPA受到了極大的支持和贊揚,其中就包括了Spring與EJB3.0的開發團隊。

註意:JPA是一套規範,不是一套產品,那麽像Hibernate,TopLink,JDO他們是一套產品,如果說這些產品實現了這個JPA規範,那麽我們就可以叫他們為JPA的實現產品。

Spring Data JPA 是 Spring 基於 ORM 框架、JPA 規範的基礎上封裝的一套JPA應用框架,可使開發者用極簡的代碼即可實現對數據的訪問和操作。它提供了包括增刪改查等在內的常用功能,且易於擴展!學習並使用 Spring Data JPA 可以極大提高開發效率!(spring data jpa讓我們解脫了DAO層的操作,基本上所有CRUD都可以依賴於它來實現

摘自:springboot(五):spring data jpa的使用——純潔的微笑

Hibernate 和 MyBatis 簡單對比

由於JPA底層幹活的仍然是Hibernate框架,而我們之前學習的只有MyBatis相關的東西,所以在嘗鮮之前還是有必要簡單了解一下兩者的區別:

Hibernate的優勢:

  • Hibernate的DAO層開發比MyBatis簡單,Mybatis需要維護SQL和結果映射。
  • Hibernate對對象的維護和緩存要比MyBatis好,對增刪改查的對象的維護要方便。
  • Hibernate數據庫移植性很好,MyBatis的數據庫移植性不好,不同的數據庫需要寫不同SQL。
  • Hibernate有更好的二級緩存機制,可以使用第三方緩存。MyBatis本身提供的緩存機制不佳。

MyBatis的優勢:

  • MyBatis可以進行更為細致的SQL優化,可以減少查詢字段。
  • MyBatis容易掌握,而Hibernate門檻較高。

簡單總結:

  • MyBatis:小巧、方便、高效、簡單、直接、半自動化
  • Hibernate:強大、方便、高效、復雜、間接、全自動化

引用自:【持久化框架】Mybatis與Hibernate的詳細對比——高亮

CRUD + 分頁後臺實例

下面我們來快速搭建一個使用Spring-DATA-JPA的CRUD+分頁後臺實例,並且我們會直接使用到RESTful API(不熟悉的同學戳這裏)

第一步:新建SpringBoot項目

打開IDEA新建一個SpringBoot項目,不熟悉SpringBoot的同學請右轉:【傳送門】,然後在pom.xml中添加以下依賴:

<!-- mysql-->
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>5.1.21</version>
</dependency>

<!-- 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/testdb?useUnicode=true&characterEncoding=utf-8
spring.datasource.username=root
spring.datasource.password=123456
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.jpa.properties.hibernate.hbm2ddl.auto=update
#顯示SQL語句
spring.jpa.show-sql=true
#不加下面這句則默認創建MyISAM引擎的數據庫
spring.jpa.database-platform=org.hibernate.dialect.MySQL5InnoDBDialect
#自己重寫的配置類,默認使用utf8編碼
spring.jpa.properties.hibernate.dialect=com.wmyskxz.demo.config.MySQLConfig

spring.jpa.properties.hibernate.hbm2ddl.auto是hibernate的配置屬性,其主要作用是:自動創建、更新、驗證數據庫表結構。該參數的幾種配置如下:

  • create:每次加載hibernate時都會刪除上一次的生成的表,然後根據你的model類再重新來生成新表,哪怕兩次沒有任何改變也要這樣執行,這就是導致數據庫表數據丟失的一個重要原因。
  • create-drop:每次加載hibernate時根據model類生成表,但是sessionFactory一關閉,表就自動刪除。
  • update:最常用的屬性,第一次加載hibernate時根據model類會自動建立起表的結構(前提是先建立好數據庫),以後加載hibernate時根據model類自動更新表結構,即使表結構改變了但表中的行仍然存在不會刪除以前的行。要註意的是當部署到服務器後,表結構是不會被馬上建立起來的,是要等應用第一次運行起來後才會。
  • validate:每次加載hibernate時,驗證創建數據庫表結構,只會和數據庫中的表進行比較,不會創建新表,但是會插入新值。

然後新建一個【config】包,創建一個【MySQLConfig】類(上面的spring.jpa.properties.hibernate.dialect屬性就要配置這裏的類全路徑):

package com.wmyskxz.demo.config;

import org.hibernate.dialect.MySQL5InnoDBDialect;

public class MySQLConfig extends MySQL5InnoDBDialect {
    @Override
    public String getTableTypeString() {
        return "ENGINE=InnoDB DEFAULT CHARSET=utf8";
    }
}

第二步:創建好需要的數據庫

打開SQL服務,建表語句也很簡單啦:

create database testdb;

第三步:創建實體類

實體類映射的實際上是數據庫表的結構,在適當的包目錄下(例如【entity】)下創建好實體類:

package com.wmyskxz.demo.entity;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;

@Entity // 表明這是個實體類
public class User {

    @Id // 表明這個屬性是主鍵
    @GeneratedValue // 自增長
    private long id;
    @Column(nullable = false, unique = true)    // 不允許為空,屬性唯一
    private String username;
    @Column(nullable = false)   // 不允許為空
    private String password;

    // getter and setter
}

第四步:DAO層

新建一個【repository】包,然後新建一個【UserRepository】接口,並繼承JpaRepository類:

package com.wmyskxz.demo.repository;

import com.wmyskxz.demo.entity.User;
import org.springframework.data.jpa.repository.JpaRepository;

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

繼承JpaRepository需要傳入兩個參數,一個是實體類User一個是主鍵的類型Long,而凡是繼承了JpaRepository類的就會自動實現很多內置的方法,包括增刪改查,以及使用默認支持的Pageable對象來進行分頁,默認的方法大致如下:

public interface JpaRepository<T, ID> extends PagingAndSortingRepository<T, ID>, QueryByExampleExecutor<T> {
    List<T> findAll();
    List<T> findAll(Sort var1);
    List<T> findAllById(Iterable<ID> var1);
    <S extends T> List<S> saveAll(Iterable<S> var1);
    void flush();
    <S extends T> S saveAndFlush(S var1);
    void deleteInBatch(Iterable<T> var1);
    void deleteAllInBatch();
    T getOne(ID var1);
    <S extends T> List<S> findAll(Example<S> var1);
    <S extends T> List<S> findAll(Example<S> var1, Sort var2);
}

第五步:Controller層

新建【controller】包,新建一個【UserController】類,編寫簡單的增刪改查代碼:

package com.wmyskxz.demo.controoler;

import com.wmyskxz.demo.entity.User;
import com.wmyskxz.demo.repository.UserRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Sort;
import org.springframework.web.bind.annotation.*;

import java.util.Optional;

@RestController // 表明這是一個Controller並返回JSON格式
public class UserController {
    @Autowired
    private UserRepository userRepository;

    @GetMapping("/getOne")
    public Optional<User> getOneUserById(@RequestParam long id) {
        return userRepository.findById(id);
    }

    @GetMapping("/all")
    public Iterable<User> getAllUsers(@RequestParam(value = "page", defaultValue = "0") int page,
                                      @RequestParam(value = "size", defaultValue = "5") int size) {
        page = page < 0 ? 0 : page;// 如果page為負數則修改為0,防止在首頁點擊上一頁發生錯誤
        Sort sort = new Sort(Sort.Direction.DESC, "id");// 按id倒敘排列
        return userRepository.findAll(new PageRequest(page, size, sort));
    }

    @PostMapping("/add")
    public String addUser(@RequestParam String username,
                          @RequestParam String password) {
        User user = new User();
        user.setUsername(username);
        user.setPassword(password);
        userRepository.save(user);// 註意這裏是save
        return "Saved";
    }

    @DeleteMapping("/delete")
    public String deleteUserById(@RequestParam long id) {
        userRepository.deleteById(id);
        return "Deleted";
    }

    @PutMapping("/update")
    public String updateUser(User user) {
//        User user = new User();
//        user.setId(id);
//        user.setUsername(username);
//        user.setPassword(password);
        userRepository.save(user);
        return "Updated";
    }
}

上面就直接使用@Autowired自動引入了繼承了JpaRepository的UserRepository接口,我們使用它默認的方法已經足夠完成我們的基礎功能了,值得一提的是我們的getAllUsers(...)方法,它往findAll()方法裏傳入了一個Pageable對象,這是Spring Data庫中定義的一個接口,是所有分頁相關信息的一個抽象,通過該接口,我們可以得到和分頁相關的所有信息(例如pageNumberpageSize等),這樣Jpa就能夠通過Pageable參數來得到一個帶分頁信息的Sql語句。

當然上面我們是通過自己創建了一個Pageable對象,Spring也支持直接獲取Pageable對象,可以把上面的getAllUsers(...)方法改寫成下面這樣:

@GetMapping("/all")
public Iterable<User> getAllUsers(@PageableDefault(value = 5, sort = {"id"}, direction = Sort.Direction.DESC) 
                                              Pageable pageable) {
    return userRepository.findAll(pageable);
}

默認從第0頁開始,也可以自己傳入一個page參數,跟上面的是一樣的。

第六步:運行項目

上面我們就快速搭建起來了一個基於Spring Boot和JPA的REST風格的後臺增刪改查實例,我們把項目跑起來,可以看到數據庫自動創建了一些表:

技術分享圖片

JPA幫我們創建的user表的創建SQL如下:

CREATE TABLE `user` (
  `id` bigint(20) NOT NULL,
  `password` varchar(255) NOT NULL,
  `username` varchar(255) NOT NULL,
  PRIMARY KEY (`id`),
  UNIQUE KEY `UK_sb8bbouer5wak8vyiiy4pf2bx` (`username`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

使用REST測試工具測試

完全符合我們的要求,然後我們使用一些REST的測試工具,來測試上面的功能是否都能正確運行,比如我這裏使用的【Restlet Client】,在Chrome商店就可以下載到。

/all地址測試:

首先先來測試一下http://localhost:8080/all地址,由於現在數據庫還是空的,所以可以看到返回如下:

{
    "content": [
    ],
    "pageable": {
        "sort": {
            "sorted": true,
            "unsorted": false,
            "empty": false
        },
        "offset": 0,
        "pageNumber": 0,
        "pageSize": 5,
        "unpaged": false,
        "paged": true
    },
    "totalElements": 0,
    "last": true,
    "totalPages": 0,
    "number": 0,
    "size": 5,
    "sort": {
        "sorted": true,
        "unsorted": false,
        "empty": false
    },
    "numberOfElements": 0,
    "first": true,
    "empty": true
}

添加用戶測試:

然後我們使用http://localhost:8080/add?username=wmyskxz&password=123地址,添加幾個類似的用戶信息:

技術分享圖片

可以看到返回正確的Saved信息:

技術分享圖片

/getOne地址測試:

我們就直接使用http://localhost:8080/getOne?id=1來獲取剛才添加的用戶,可以看到返回正確的數據:

{
    "id": 1,
    "username": "wmyskxz",
    "password": "123"
}

修改用戶測試:

然後我們使用http://localhost:8080/update?id=1&username=wmyskxz&password=123456來模擬進行用戶密碼的修改:

技術分享圖片

可以看到正確的更新信息Updated,再次查詢用戶,也能看到正確的數據:

{
    "id": 1,
    "username": "wmyskxz",
    "password": "123456"
}

分頁測試:

我們使用添加功能為數據庫添加5條以上的數據,然後進行一次查詢/all,可以看到能夠按照id倒敘排列後返回5條數據:

技術分享圖片

返回的JSON數據如下:

{
    "content": [
        {
            "id": 10,
            "username": "wmyskxz8",
            "password": "123"
        },
        {
            "id": 9,
            "username": "wmyskxz7",
            "password": "123"
        },
        {
            "id": 8,
            "username": "wmyskxz6",
            "password": "123"
        },
        {
            "id": 7,
            "username": "wmyskxz5",
            "password": "123"
        },
        {
            "id": 6,
            "username": "wmyskxz4",
            "password": "123"
        }
    ],
    "pageable": {
        "sort": {
            "sorted": true,
            "unsorted": false,
            "empty": false
        },
        "offset": 0,
        "pageNumber": 0,
        "pageSize": 5,
        "unpaged": false,
        "paged": true
    },
    "totalElements": 9,
    "last": false,
    "totalPages": 2,
    "number": 0,
    "size": 5,
    "sort": {
        "sorted": true,
        "unsorted": false,
        "empty": false
    },
    "numberOfElements": 5,
    "first": true,
    "empty": false
}

刪除用戶測試:

使用地址http://localhost:8080/delete?id=1來刪除ID為1的用戶:

技術分享圖片

能正確看到Deleted信息,並查看數據能夠看到數據已經被刪除了。


以上,我們就快速搭建好了一個CRUD+分頁的後臺實例,還用了比較流行的RESTful風格,粗略的感受了一下JPA的方便,還是挺爽的..沒有復雜的Mapper文件,不用自動生成實體,甚至不用管SQL,只需要專註在邏輯上就行了,其實簡單使用的話以上的東西也能應付一些常見的場景了,後期再深入了解了解吧!

參考資料:
springboot(五):spring data jpa的使用——純潔的微笑
springboot(十五):springboot+jpa+thymeleaf增刪改查示例——純潔的微笑
Spring Boot中使用Spring-data-jpa讓數據訪問更簡單、更優雅——程序猿DD

歡迎轉載,轉載請註明出處!
簡書ID:@我沒有三顆心臟
github:wmyskxz
歡迎關註公眾微信號:wmyskxz
分享自己的學習 & 學習資料 & 生活
想要交流的朋友也可以加qq群:3382693

Spring-Data-JPA嘗鮮:快速搭建CRUD+分頁後臺實例