首頁 > 軟體

Spring Boot 整合持久層之Spring Data JPA

2022-08-13 18:01:36

整合Spring Data JPA

JPA (Java Persistence API)和 Spring Data 是兩個範疇的概念。

Hibernate 是一個 ORM 框架,JPA 則是一種ORM,JPA 和 Hibernate 的關係就像 JDBC 與 JDBC 驅動,即 JPA 制定了 ORM 規範,而 Hibernate 是這些規範的實現(事實上,是現有 Hibernate 後有 JPA ,JPA 規範的起草也是 Hibernate 的作者),因此從功能上來說,JPA 相當於 Hibernate 的一個子集。

Spring Data 是 Spring 的一個子專案,致力於簡化資料庫存取,通過規範的方法名稱來分析開發者的意圖,進而減少資料庫存取層的程式碼量。Spring Data 不僅支援關係型資料庫,也支援非關係型資料庫。Spring Data JPA 可以有效簡化關係型資料庫存取程式碼。

Spring Boot 整合 Spring Data JPA 步驟如下:

1. 建立資料庫

建立資料庫即可,不用建立表

建立資料庫 jpa,如下

create database `jpa` default character set utf8;

2. 建立專案

建立 Spring Boot 專案,新增 MySQL 和 Spring Data JPA 的依賴

<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
  <groupId>com.alibaba</groupId>
  <artifactId>druid</artifactId>
  <version>1.1.9</version>
</dependency>
<dependency>
  <groupId>mysql</groupId>
  <artifactId>mysql-connector-java</artifactId>
  <scope>runtime</scope>
</dependency>

3. 資料庫設定

在 application.properties 中設定資料庫基本資訊以及 JPA 相關設定

# 資料庫基本設定
spring.datasource.type=com.alibaba.druid.pool.DruidDataSource
spring.datasource.url=jdbc:mysql://localhost:3306/jpa?useUnicode=true&characterEncoding=utf8&useSSL=true
spring.datasource.username=root
spring.datasource.password=root
# JPA 設定
spring.jpa.show-sql=true
spring.jpa.database=mysql
spring.jpa.hibernate.ddl-auto=update
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL57Dialect

4. 建立實體類

@Entity(name = "t_book")
public class Book {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Integer id;
    @Column(name = "book_name",nullable = false)
    private String name;
    private String author;
    private Float price;
    @Transient
    private String description;
    @Override
    public String toString() {
        return "Book{" +
                "id=" + id +
                ", name='" + name + ''' +
                ", author='" + author + ''' +
                ", price=" + price +
                ", description='" + description + ''' +
                '}';
    }
    public String getDescription() {
        return description;
    }
    public void setDescription(String description) {
        this.description = description;
    }
    public Integer getId() {
        return id;
    }
    public void setId(Integer id) {
        this.id = id;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public String getAuthor() {
        return author;
    }
    public void setAuthor(String author) {
        this.author = author;
    }
    public Float getPrice() {
        return price;
    }
    public void setPrice(Float price) {
        this.price = price;
    }
}

程式碼解釋:

  • @Entity 註解表示該類是一個實體類,在專案啟動時會根據該類生成一張表,表的名稱即 @Entity 註解中的 name 的值,如果不設定 name ,預設表名為類名
  • 所有的實體類都要有主鍵,@Id 註解表示改屬性是一個主鍵,@GeneratedValue 註解表示主鍵自動生成,strategy 表示生成主鍵的策略
  • 預設情況下,生成的表中欄位的名稱就是實體類中屬性的名稱,通過 @Column 註解可以客製化生成的欄位的屬性,name 表示該屬性對應的資料表中欄位的名稱,nullable 表示該欄位非空
  • @Transient 註解表示在生成資料庫中的表時,該屬性被忽略,即不生成對應的欄位

5. 建立 BookDao 介面

public interface BookDao extends JpaRepository<Book, Integer> {
    List<Book> getBooksByAuthorStartingWith(String author);
    List<Book> getBooksByPriceGreaterThan(Float price);
    @Query(value = "select * from t_book where id=(select max(id) from t_book)", nativeQuery = true)
    Book getMaxIdBook();
    @Query("select b from t_book b where b.id>:id and b.author=:author")
    List<Book> getBookByIdAndAuthor(@Param("author") String author, @Param("id") Integer id);
    @Query("select b from t_book b where b.id<?2 and b.name like %?1%")
    List<Book> getBooksByIdAndName(String name, Integer id);
}

程式碼解釋:

  • 自定義 BookDao 繼承 JpaRepository 。JpaRepository 中提供了一些基本的資料庫操作方法,有基本的增刪改查、分頁查詢、排序查詢等
  • getBooksByAuthorStartingWith() 方法表示查詢以某個字元開始的所有的書
  • getBooksByPriceGreaterThan() 方法表示查詢單價大於某個值的所有書
  • 在Spring Data JPA 中,只要方法的定義符合既定規範,Spring Data JPA 就能分析出開發者的意圖,從而避免開發中定義 SQL 。 所謂的既定規範,就是一定的方法命名規則,支援的命名規則如下:

| 關鍵字 | 方法命名 | sql where字句 |

| — | — | — |

| And | findByNameAndPwd | where name= ? and pwd =? |

| Or | findByNameOrSex | where name= ? or sex=? |

| Is,Equals | findById,findByIdEquals | where id= ? |

| Between | findByIdBetween | where id between ? and ? |

| LessThan | findByIdLessThan | where id < ? |

| LessThanEqual | findByIdLessThanEqual | where id <= ? |

| GreaterThan | findByIdGreaterThan | where id > ? |

| GreaterThanEqual | findByIdGreaterThanEqual | where id > = ? |

| After | findByIdAfter | where id > ? |

| Before | findByIdBefore | where id < ? |

| IsNull | findByNameIsNull | where name is null |

| isNotNull,NotNull | findByNameNotNull | where name is not null |

| Like | findByNameLike | where name like ? |

| NotLike | findByNameNotLike | where name not like ? |

| StartingWith | findByNameStartingWith | where name like ‘?%’ |

| EndingWith | findByNameEndingWith | where name like ‘%?’ |

| Containing | findByNameContaining | where name like ‘%?%’ |

| OrderBy | findByIdOrderByXDesc | where id=? order by x desc |

| Not | findByNameNot | where name <> ? |

| In | findByIdIn(Collection<?> c) | where id in (?) | | NotIn | findByIdNotIn(Collection<?> c) | where id not in (?) |

| True | findByAaaTue | where aaa = true |

| False | findByAaaFalse | where aaa = false |

| IgnoreCase | findByNameIgnoreCase | where UPPER(name)=UPPER(?) |

  • 既定的方法命名規則不一定滿足所有的開發需求,因此 Spring Data JPA 也支援自定義 JPQL 或者原生 SQL 。getMaxIdBook() 方法表示查詢id最大的書,nativeQuery = true 表示使用原生的 SQL 查詢
  • getBookByIdAndAuthor() 表示根據 id 和 author 進行查詢,這裡使用預設的 JPQL 語句。JPQL 是一種物件導向表示式語言,可以將 SQL 語法和簡單查詢語句繫結在一起,使用這種語言編寫的查詢是可以移植的,可以被編譯成所有主流資料庫伺服器上的 SQL 。JPQL 與原生 SQL 語句類似,並且完全物件導向,通過類名和屬性存取,而不是表名和表的屬性。getBookByIdAndAuthor() 方法使用 :id、:name 這種方式來進行引數繫結。注意:這裡使用的列名是屬性名稱,而不是資料庫中的列的名稱。
  • getBooksByIdAndName() 方法也是自定義 JPQL 查詢,不同的是傳參使用 ?1、?2 這種方式。注意:方法中的引數的順序要與引數宣告的順序一致
  • 如果 BookDao 中的方法設計修改操作,就需要新增 @Modifying 註解並新增事務

6. 建立 BookService

@Service
public class BookService {
    @Autowired
    BookDao bookDao;
    public void addBook(Book book) {
        bookDao.save(book);
    }
    public Page<Book> getBookByPage(Pageable pageable) {
        return bookDao.findAll(pageable);
    }
    public List<Book> getBooksByAuthorStartingWith(String author) {
        return bookDao.getBooksByAuthorStartingWith(author);
    }
    public List<Book> getBooksByPriceGreaterThan(Float price) {
        return bookDao.getBooksByPriceGreaterThan(price);
    }
    public Book getMaxIdBook() {
        return bookDao.getMaxIdBook();
    }
    public List<Book> getBookByIdAndAuthor(String author, Integer id) {
        return bookDao.getBookByIdAndAuthor(author, id);
    }
    public List<Book> getBooksByIdAndName(String name, Integer id) {
        return bookDao.getBooksByIdAndName(name, id);
    }
}

程式碼解釋:

  • bookDao.save(book) 標識將物件資料儲存到資料庫,save 方法由 JpaRepository 介面提供
  • bookDao.findAll(pageable) 是一個分頁查詢,使用 findAll 方法,返回值為 Page ,該物件中包含有分頁常用資料,例如總記錄數,總頁數、每頁記錄數、當前頁記錄數等

7. 建立 BookController

@RestController
public class BookController {
    @Autowired
    BookService bookService;
    @GetMapping("/findAll")
    public void findAll() {
        PageRequest pageable = PageRequest.of(2, 3);
        Page<Book> page = bookService.getBookByPage(pageable);
        System.out.println("總頁數:"+page.getTotalPages());
        System.out.println("總記錄數:"+page.getTotalElements());
        System.out.println("查詢結果:"+page.getContent());
        System.out.println("當前頁數:"+(page.getNumber()+1));
        System.out.println("當前頁記錄數:"+page.getNumberOfElements());
        System.out.println("每頁記錄數:"+page.getSize());
    }
    @GetMapping("/search")
    public void search() {
        List<Book> bs1 = bookService.getBookByIdAndAuthor("魯迅", 7);
        List<Book> bs2 = bookService.getBooksByAuthorStartingWith("吳");
        List<Book> bs3 = bookService.getBooksByIdAndName("西", 8);
        List<Book> bs4 = bookService.getBooksByPriceGreaterThan(30F);
        Book b = bookService.getMaxIdBook();
        System.out.println("bs1:"+bs1);
        System.out.println("bs2:"+bs2);
        System.out.println("bs3:"+bs3);
        System.out.println("bs4:"+bs4);
        System.out.println("b:"+b);
    }
    @GetMapping("/save")
    public void save() {
        Book book = new Book();
        book.setAuthor("魯迅");
        book.setName("吶喊");
        book.setPrice(23F);
        bookService.addBook(book);
    }
}

程式碼解釋:

  • 在 findAll 介面中,首先通過呼叫 PageRequest 中的 of 方法構造 PageRequest 物件。of 方法接收兩個引數:第一個引數是頁數,從 0 開始計;第二個引數是每頁顯示的條數
  • 在save 介面中構造一個 Book 物件,直接呼叫 save 方法儲存即可

8. 測試

啟動專案,檢視資料庫發現 t_book 表已自動新建,新增測試資料

INSERT INTO `jpa`.`t_book`(`id`, `author`, `book_name`, `price`) VALUES (1, '羅貫中', '三國演義', 30);
INSERT INTO `jpa`.`t_book`(`id`, `author`, `book_name`, `price`) VALUES (2, '曹雪芹', '紅樓夢', 35);
INSERT INTO `jpa`.`t_book`(`id`, `author`, `book_name`, `price`) VALUES (3, '吳承恩', '西遊記', 29);
INSERT INTO `jpa`.`t_book`(`id`, `author`, `book_name`, `price`) VALUES (4, '施耐庵', '水滸傳', 29);
INSERT INTO `jpa`.`t_book`(`id`, `author`, `book_name`, `price`) VALUES (5, '錢鍾書', '宋詩選注', 33);
INSERT INTO `jpa`.`t_book`(`id`, `author`, `book_name`, `price`) VALUES (6, '魯迅', '朝花夕拾', 18);
INSERT INTO `jpa`.`t_book`(`id`, `author`, `book_name`, `price`) VALUES (7, '魯迅', '故事新編', 22);

然後呼叫 /findAll 介面,控制檯列印紀錄檔如下:

Hibernate: select book0_.id as id1_0_, book0_.author as author2_0_, book0_.book_name as book_nam3_0_, book0_.price as price4_0_ from t_book book0_ limit ?, ?
總頁數:3
總記錄數:7
查詢結果:[Book{id=7, name='故事新編', author='魯迅', price=22.0, description='null'}]
當前頁數:3
當前頁記錄數:1
每頁記錄數:3

接著呼叫 /save 介面 ,檢視資料庫表資料,如下

最後呼叫 /search 介面,控制檯列印紀錄檔如下

Hibernate: select book0_.id as id1_0_, book0_.author as author2_0_, book0_.book_name as book_nam3_0_, book0_.price as price4_0_ from t_book book0_ where book0_.id>? and book0_.author=?
Hibernate: select book0_.id as id1_0_, book0_.author as author2_0_, book0_.book_name as book_nam3_0_, book0_.price as price4_0_ from t_book book0_ where book0_.author like ? escape ?
Hibernate: select book0_.id as id1_0_, book0_.author as author2_0_, book0_.book_name as book_nam3_0_, book0_.price as price4_0_ from t_book book0_ where book0_.id<? and (book0_.book_name like ?)
Hibernate: select book0_.id as id1_0_, book0_.author as author2_0_, book0_.book_name as book_nam3_0_, book0_.price as price4_0_ from t_book book0_ where book0_.price>?
Hibernate: select * from t_book where id=(select max(id) from t_book)
bs1:[Book{id=8, name='吶喊', author='魯迅', price=23.0, description='null'}]
bs2:[Book{id=3, name='西遊記', author='吳承恩', price=29.0, description='null'}]
bs3:[Book{id=3, name='西遊記', author='吳承恩', price=29.0, description='null'}]
bs4:[Book{id=2, name='紅樓夢', author='曹雪芹', price=35.0, description='null'}, Book{id=5, name='宋詩選注', author='錢鍾書', price=33.0, description='null'}]
b:Book{id=8, name='吶喊', author='魯迅', price=23.0, description='null'}

到此這篇關於Spring Boot 整合持久層之Spring Data JPA的文章就介紹到這了,更多相關Spring Boot Spring Data JPA內容請搜尋it145.com以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援it145.com!


IT145.com E-mail:sddin#qq.com