JPA(Java Persistence API)是Sun官方提出的Java持久化規範,它爲Java開發人員提供了一種對象/關聯映射工具來管理Java應用中的關係數據。html
Hibernate是JPA目前最流行的實現,JPA的制定很大程度上吸取了的思想,spring-boot-starter-data-jpa默認使用的Hibernate。java
JPA的優點:spring
標準化sql
JPA 是 JCP 組織發佈的 Java EE 標準之一,所以任何聲稱符合 JPA 標準的框架都遵循一樣的架構,提供相同的訪問API,這保證了基於JPA開發的企業應用可以通過少許的修改就可以在不一樣的JPA框架下運行。數據庫
容器級特性的支持編程
JPA框架中支持大數據集、事務、併發等容器級事務,這使得 JPA 超越了簡單持久化框架的侷限,在企業應用發揮更大的做用。設計模式
簡單方便服務器
JPA的主要目標之一就是提供更加簡單的編程模型:在JPA框架下建立實體和建立Java 類同樣簡單,沒有任何的約束和限制,只須要使用 javax.persistence.Entity進行註釋,JPA的框架和接口也都很是簡單,沒有太多特別的規則和設計模式的要求,開發者能夠很容易的掌握。JPA基於非侵入式原則設計,所以能夠很容易的和其它框架或者容器集成。session
查詢能力架構
JPA的查詢語言是面向對象而非面向數據庫的,它以面向對象的天然語法構造查詢語句,能夠當作是Hibernate HQL的等價物。JPA定義了獨特的JPQL(Java Persistence Query Language),JPQL是EJB QL的一種擴展,它是針對實體的一種查詢語言,操做對象是實體,而不是關係數據庫的表,並且可以支持批量更新和修改、JOIN、GROUP BY、HAVING 等一般只有 SQL 纔可以提供的高級查詢特性,甚至還可以支持子查詢。
高級特性
JPA 中可以支持面向對象的高級特性,如類之間的繼承、多態和類之間的複雜關係,這樣的支持可以讓開發者最大限度的使用面向對象的模型設計企業應用,而不須要自行處理這些特性在關係數據庫的持久化。
註解 | 解釋 |
---|---|
@Entity | 聲明類爲實體或表。 |
@Table | 聲明表名。 |
@Basic | 指定非約束明確的各個字段。 |
@Embedded | 指定類或它的值是一個可嵌入的類的實例的實體的屬性。 |
@Id | 指定的類的屬性,用於識別(一個表中的主鍵)。 |
@GeneratedValue | 指定如何標識屬性能夠被初始化,例如自動、手動、或從序列表中得到的值。 |
@Transient | 指定的屬性,它是不持久的,即:該值永遠不會存儲在數據庫中。 |
@Column | 指定持久屬性欄屬性。 |
@SequenceGenerator | 指定在@GeneratedValue註解中指定的屬性的值。它建立了一個序列。 |
@TableGenerator | 指定在@GeneratedValue批註指定屬性的值發生器。它創造了的值生成的表。 |
@AccessType | 這種類型的註釋用於設置訪問類型。若是設置@AccessType(FIELD),則能夠直接訪問變量而且不須要getter和setter,但必須爲public。若是設置@AccessType(PROPERTY),經過getter和setter方法訪問Entity的變量。 |
@JoinColumn | 指定一個實體組織或實體的集合。這是用在多對一和一對多關聯。 |
@UniqueConstraint | 指定的字段和用於主要或輔助表的惟一約束。 |
@ColumnResult | 參考使用select子句的SQL查詢中的列名。 |
@ManyToMany | 定義了鏈接表之間的多對多一對多的關係。 |
@ManyToOne | 定義了鏈接表之間的多對一的關係。 |
@OneToMany | 定義了鏈接表之間存在一個一對多的關係。 |
@OneToOne | 定義了鏈接表之間有一個一對一的關係。 |
@NamedQueries | 指定命名查詢的列表。 |
@NamedQuery | 指定使用靜態名稱的查詢。 |
<parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.1.2.RELEASE</version> <relativePath/> <!-- JDK>=1.8 --> </parent> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-jpa</artifactId> </dependency> <dependency> <groupId>com.h2database</groupId> <artifactId>h2</artifactId> <scope>runtime</scope> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <optional>true</optional> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> </dependencies>
# DataSource Config spring: datasource: driver-class-name: org.h2.Driver url: jdbc:h2:mem:test username: root password: test jpa: show-sql: true hibernate: ddl-auto: update
jpa.hibernate.show-sql是jpa通用配置,能夠打印SQL,對於調試很是重要
jpa.hibernate.ddl-auto是hibernate的配置屬性,其主要做用是:自動建立、更新、驗證數據庫表結構。該參數的幾種配置以下:
package com.example.jpa.entity; import lombok.Data; import lombok.ToString; import javax.persistence.*; //必須註解,聲明這個類是一個實體 @Entity //可選註解,能夠初始化建表信息,甚至徹底定製建表SQL,默認的name(表名)便是類名 @Table(name = "USER") @Data @ToString public class User { //聲明這個屬性對應表中惟一標識(主鍵)字段 @Id //可選,主鍵自增,默認GenerationType.AUTO @GeneratedValue private Long id; //聲明這個屬性對應表中某個字段,其中全部配置屬性都是可選的,但length默認爲255,建議手動指定以配置一個合適的長度 @Column(name = "name", nullable = true, length = 20) private String name; @Column(name = "age", length = 3) private Integer age; @Column(name = "email", length = 50) private String email; }
package com.example.jpa.repository; import com.example.jpa.entity.User; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.Query; import org.springframework.data.repository.query.Param; import org.springframework.stereotype.Repository; import java.util.List; //必選註解,聲明這是一個倉儲 @Repository //實現org.springframework.data.repository即便用了JPA //org.springframework.data.jpa.repository.JpaRepository實現了一些經常使用數據庫操做 //因此通常都選擇繼承JpaRepository以簡化代碼 public interface UserRepository extends JpaRepository<User,Long> { //按照JPA規則自定義接口 public List<User> getByName(String name); //自定義PQL //nativeQuery=true則使用原生sql,更靈活,但失去了自動適應數據庫產品的能力,通常不推薦 @Query(countQuery = "SELECT COUNT(U.AGE) FROM USER U WHERE U.AGE = :age") public int countUsersByAge(@Param("age") int age); }
JPQL規則常見關鍵字一覽表
Keyword | Sample | JPQL snippet |
---|---|---|
And | findByLastnameAndFirstname | … where x.lastname = ?1 and |
Or | findByLastnameOrFirstname | … where x.lastname = ?1 or x.firstname = ?2 |
Is,Equals | 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) |
package com.example.jpa; import com.example.jpa.entity.User; import com.example.jpa.repository.UserRepository; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.test.context.junit4.SpringRunner; import java.util.List; @RunWith(SpringRunner.class) @SpringBootTest public class JpaApplicationTests { @Autowired UserRepository userRepository; @Before public void before(){ User user = new User(); user.setName("蟲師"); user.setAge(123); user.setEmail("xiaoyu@demo.com"); userRepository.save(user); user = new User(); user.setName("泰密"); user.setAge(16); user.setEmail("taimi@demo.com"); userRepository.save(user); } @Test public void contextLoads() { User user = new User(); user.setName("指揮官"); user.setAge(16); user.setEmail("xiaohong@demo.com"); //spring提供的插入功能 User save = userRepository.save(user); System.out.println("----插入-----\n" .concat(save.toString()) .concat("\n----查詢全部----")); //spring提供的查詢功能 List<User> all = userRepository.findAll(); all.forEach(System.out::println); //自定義的查詢功能 List<User> list = userRepository.getByName("蟲師"); System.out.println("-----自定義接口------\n" .concat(list.toString())); //自定義計數功能 int i = userRepository.countUsersByAge(16); System.out.println("-----自定義PQL------\n" .concat(String.valueOf(i))); } }
Hibernate: call next value for hibernate_sequence Hibernate: insert into user (age, email, name, id) values (?, ?, ?, ?) Hibernate: call next value for hibernate_sequence Hibernate: insert into user (age, email, name, id) values (?, ?, ?, ?) Hibernate: call next value for hibernate_sequence Hibernate: insert into user (age, email, name, id) values (?, ?, ?, ?) ----插入----- User(id=3, name=指揮官, age=16, email=xiaohong@demo.com) ----查詢全部---- 2019-01-31 15:55:19.482 INFO 3144 --- [ main] o.h.h.i.QueryTranslatorFactoryInitiator : HHH000397: Using ASTQueryTranslatorFactory Hibernate: select user0_.id as id1_0_, user0_.age as age2_0_, user0_.email as email3_0_, user0_.name as name4_0_ from user user0_ User(id=1, name=蟲師, age=123, email=xiaoyu@demo.com) User(id=2, name=泰密, age=16, email=taimi@demo.com) User(id=3, name=指揮官, age=16, email=xiaohong@demo.com) Hibernate: select user0_.id as id1_0_, user0_.age as age2_0_, user0_.email as email3_0_, user0_.name as name4_0_ from user user0_ where user0_.name=? -----自定義接口------ [User(id=1, name=蟲師, age=123, email=xiaoyu@demo.com)] Hibernate: select count(user0_.id) as col_0_0_ from user user0_ where user0_.age=? -----自定義PQL------ 2