一. JPA簡介
1. JPA概念
JPA是Sun官方提出的Java持久化規範,是Java Persistence API的簡稱,中文名‘Java持久層API’,它本質上是一種ORM規範。
JPA通過 JDK 5.0 的 註解或XML 兩種形式來描述 ‘對象--關係表’ 的映射關係,並將運行期的實體對象持久化到數據庫中。
2. JPA出現的原因
Sun引入 JPA 規範是出於兩個原因:
- 1. 簡化現有Java EE和Java SE的開發工作;
- 2. Sun希望整合ORM技術,實現天下歸一。
也就是說,Sun提出JPA規範的目的就是想以官方身份來統一各種ORM框架的規範,包括著名的Hibernate、TopLink等。這樣就可以避免開發者爲了使用Hibernate,要學習一套ORM框架;爲了使用TopLink框架,又要再學習一套ORM框架,免去了重複學習的過程!
3. JPA涵蓋的技術
JPA的總體思想和現有的Hibernate、TopLink、JDO、Mybatis等ORM框架大體一致。
總的來說,JPA包括以下3方面的技術:
(1).ORM映射元數據
JPA支持XML和JDK 5.0中的註解兩種形式,通過元數據描述對象和表之間的映射關係,框架據此將實體對象持久化到數據庫表中。
(2).JPA的API
用來操作實體對象,執行CRUD操作,框架在後臺替我們完成所有的事情,開發者從繁瑣的JDBC和SQL代碼中解脫出來。
(3).查詢語言
通過面向對象而非面向數據庫的查詢語言查詢數據,避免程序的SQL語句緊密耦合。
4. JPA與其他ORM框架的關係
JPA的本質是一種ORM規範(不是ORM框架,因爲JPA並未提供ORM實現,只是制定了規範),而非實現。
它只提供了一些相關的接口,但是這些接口並不能直接使用,JPA的底層需要某種JPA實現,而Hibernate等框架則是對JPA的一種具體實現。
也就是說JPA僅僅是一套規範,不是一套產品, Hibernate, TopLink等都是實現了JPA規範的一套產品。
Hibernate 從3.2開始,就開始兼容JPA。Hibernate3.2獲得了Sun TCK的 JPA(Java Persistence API)兼容認證。
所以JPA和Hibernate之間的關係,可以簡單的理解爲JPA是標準接口,Hibernate是實現,他們之間並不是對標的關係,下圖可以表明他們之間的關係。
Hibernate屬於遵循JPA規範的一種實現,但是Hibernate還有其他要實現的規範。所以它們的關係更類似於是:
JPA是一種做麪條的標準規範,而Hibernate是一種遵循做麪條規範的具體的湯麪;它不僅遵循了做麪條的規範,同時也會遵循做湯和調料的其他規範。
5. JPA中的註解
二. Spring Boot整合JPA實現過程
1. 創建web程序
我們按照之前的經驗,創建一個web程序,並將之改造成Spring Boot項目,具體過程略。
2. 添加依賴包
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.10</version>
</dependency>
3. 添加配置文件
創建application.yml配置文件
spring:
datasource:
url: jdbc:mysql://localhost:3306/db4?serverTimezone=UTC&useUnicode=true&characterEncoding=utf-8&useSSL=true
type: com.alibaba.druid.pool.DruidDataSource
username: root
password: syc
driver-class-name: com.mysql.jdbc.Driver #驅動
jpa:
hibernate:
ddl-auto: update #自動更新
show-sql: true #日誌中顯示sql語句
jpa.hibernate.ddl-auto是hibernate的配置屬性,其主要作用是:自動創建、更新、驗證數據庫表結構。
該參數的幾種配置如下:
- ·create:每次加載hibernate時都會刪除上一次的生成的表,然後根據你的model類再重新來生成新表,哪怕兩次沒有任何改變也要這樣執行,這就是導致數據庫表數據丟失的一個重要原因。
- ·create-drop:每次加載hibernate時根據model類生成表,但是sessionFactory一關閉,表就自動刪除。
- ·update:最常用的屬性,第一次加載hibernate時根據model類會自動建立起表的結構(前提是先建立好數據庫),以後加載hibernate時根據model類自動更新表結構,即使表結構改變了但表中的行仍然存在不會刪除以前的行。要注意的是當部署到服務器後,表結構是不會被馬上建立起來的,是要等應用第一次運行起來後纔會。
- ·validate:每次加載hibernate時,驗證創建數據庫表結構,只會和數據庫中的表進行比較,不會創建新表,但是會插入新值。
4. 創建實體類
package com.yyg.boot.domain;
import lombok.Data;
import lombok.ToString;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
/**
* @Author 一一哥Sun
* @Date Created in 2020/3/30
* @Description Description
*/
@Data
@ToString
@Entity
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column
private String username;
@Column
private String birthday;
@Column
private String sex;
@Column
private String address;
}
5. 創建DataSource配置類
package com.yyg.boot.config;
import com.alibaba.druid.pool.DruidDataSource;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import javax.sql.DataSource;
/**
* @Author 一一哥Sun
* @Date Created in 2020/3/30
* @Description 第二種配置數據源的方式
*/
@Data
@ComponentScan
@Configuration
@ConfigurationProperties(prefix="spring.datasource")
public class DbConfig {
private String url;
private String username;
private String password;
@Bean
public DataSource getDataSource() {
DruidDataSource dataSource = new DruidDataSource();
dataSource.setUrl(url);
dataSource.setUsername(username);
dataSource.setPassword(password);
return dataSource;
}
}
6. 創建JPA實體倉庫
package com.yyg.boot.repository;
import com.yyg.boot.domain.User;
import org.springframework.data.jpa.repository.JpaRepository;
/**
* @Author 一一哥Sun
* @Date Created in 2020/3/31
* @Description Description
*/
public interface UserRepository extends JpaRepository<User, Long> {
}
7. 創建Controller測試接口
package com.yyg.boot.web;
import com.yyg.boot.domain.User;
import com.yyg.boot.repository.UserRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.List;
/**
* @Author 一一哥Sun
* @Date Created in 2020/3/31
* @Description Description
*/
@RestController
@RequestMapping("/user")
public class UserController {
@Autowired
private UserRepository userRepository;
@GetMapping("")
public List<User> findUsers() {
return userRepository.findAll();
}
/**
* 注意:記得添加@RequestBody註解,否則前端傳遞來的json數據無法被封裝到User中!
*/
@PostMapping("")
public User addUser(@RequestBody User user) {
return userRepository.save(user);
}
@DeleteMapping(path = "/{id}")
public String deleteById(@PathVariable("id") Long id) {
userRepository.deleteById(id);
return "success";
}
}
8. 創建Application啓動類
package com.yyg.boot;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
/**
* @Author 一一哥Sun
* @Date Created in 2020/3/31
* @Description Description
*/
@SpringBootApplication
public class JpaApplication {
public static void main(String[] args) {
SpringApplication.run(JpaApplication.class, args);
}
}
完整項目結構:
9. 測試接口
在瀏覽器中進行get查詢:
在postman中執行添加操作:
在postman中執行刪除操作:
10. JPA實現原理
JPA會根據方法名來生成sql查詢語句,它遵循的是Convention over configuration(約定大約配置)的原則,遵循Spring 以及JPQL定義的方法命名。
Spring提供了一套可以通過命名規則進行查詢構建的機制,這套機制會把方法名首先過濾一些關鍵字,比如 find…By, read…By, query…By, count…By 和 get…By...
然後系統會根據關鍵字將命名解析成2個子語句,第一個 By 是區分這兩個子語句的關鍵詞。這個 By 之前的子語句是查詢子語句(指明返回要查詢的對象),後面的部分是條件子語句。
如果直接就是 findBy… 返回的就是定義Respository時指定的領域對象集合,同時JPQL中也定義了豐富的關鍵字:and、or、Between等等,下面我們來看一下JPQL中有哪些關鍵字: