1 什么是JPA
1.1 JPA概念
JPA是Java Persistence API 的簡(jiǎn)稱,中文名Java持久層API,是JDK5.0注解或XML描述對(duì)象-關(guān)系表的映射關(guān)系,并將運(yùn)行期的實(shí)體對(duì)象持久化到數(shù)據(jù)庫(kù)中.
JPA有EJB3.0軟件專家組開發(fā),作為JSR-220實(shí)現(xiàn)的一部分.但它又不限于EJB3.0,你可以在Web應(yīng)用,甚至桌面應(yīng)用中使用.JPA的宗旨是為POJO提供持久化標(biāo)準(zhǔn)規(guī)范.總的來(lái)說,JPA包括以下3方面的技術(shù):
1. ORM映射元數(shù)據(jù),JPA支持XML和JDK5.0注解兩種元數(shù)據(jù)的形式,元數(shù)據(jù)描述對(duì)象和表之間的映射關(guān)系,框架據(jù)此將實(shí)體對(duì)象持久化到數(shù)據(jù)庫(kù)表中;
2. JPA的API,用來(lái)操作實(shí)體對(duì)象,執(zhí)行CRUD操作,框架在后臺(tái)替我們完成所有的事情,開發(fā)者從繁瑣的JDBC和SQL代碼中解脫出來(lái);
3. 查詢語(yǔ)言,這是持久化操作中很重要的一個(gè)方面,通過面向?qū)ο蠖敲嫦驍?shù)據(jù)庫(kù)的查詢語(yǔ)言查詢數(shù)據(jù),避免程序的SQL語(yǔ)句緊密耦合.
1.2 什么是ORM
ORM(Object-Relational Mapping) 表示對(duì)象關(guān)系映射.在面向?qū)ο蟮能浖_發(fā)中,通過ORM,就可以吧對(duì)象映射到關(guān)系型數(shù)據(jù)庫(kù)中.只要有一套程序能夠做到建立對(duì)象與數(shù)據(jù)庫(kù)的關(guān)聯(lián),操作對(duì)象就可以直接操作數(shù)據(jù)庫(kù)數(shù)據(jù),就可以說這套程序?qū)崿F(xiàn)了ORM對(duì)象關(guān)系映射.簡(jiǎn)單地說:ORM就是建立實(shí)體類和數(shù)據(jù)庫(kù)表之間的關(guān)系,從而達(dá)到操作實(shí)體類就相當(dāng)于操作數(shù)據(jù)庫(kù)表的目的.
1.3 jpa的優(yōu)勢(shì)? ?
a.標(biāo)準(zhǔn)化
JPA是JCP組織發(fā)布的JavaEE標(biāo)準(zhǔn)之一,因此任何聲稱符合JPA標(biāo)準(zhǔn)的框架都遵循同樣的架構(gòu),提供相同的訪問API,這保證了基于JPA開發(fā)的企業(yè)應(yīng)用能夠經(jīng)過少量的修改就能夠在不同的JPA框架下運(yùn)行.
b.容器級(jí)特性的支持
JPA框架中支持大數(shù)據(jù)集,事務(wù),并發(fā)等容器級(jí)事務(wù),這使得JPA超越了簡(jiǎn)單持久化框架的局限,在企業(yè)應(yīng)用發(fā)揮更大的作用
c.簡(jiǎn)單方便
JPA的主要目標(biāo)之一就是提供更加簡(jiǎn)單的編程模型:在JPA框架下創(chuàng)建實(shí)體和創(chuàng)建Java類一樣簡(jiǎn)單,沒有任何的約束和限制,只需要使用 javax.persistence.Entity進(jìn)行注釋,JPA的框架和接口也都非常簡(jiǎn)單,沒有太多特別的規(guī)則和設(shè)計(jì)模式的要求,開發(fā)者很容易的掌握,JPA基于非入侵式原則設(shè)計(jì),因此可以很容易的和其他框架或者容器集成
d.查詢能力
JPA的查詢語(yǔ)言是面向?qū)ο蠖敲嫦驍?shù)據(jù)庫(kù)的,它以面向?qū)ο蟮淖匀徽Z(yǔ)法構(gòu)造查詢語(yǔ)句,可以看成是Hibernate HQL的等價(jià)物.JPA定義了獨(dú)特的JPQL(Java Persistence Query Language),JPQL 是EJB QL 的一種擴(kuò)展,它是針對(duì)實(shí)體的一種查詢語(yǔ)言,操作對(duì)象是實(shí)體,而不是關(guān)系數(shù)據(jù)庫(kù)的表,而且能夠支持批量更新和修改,JOIN,GROUP BY,HAVING 等通常只有 SQL 才能夠提供的高級(jí)查詢特性,甚至還能夠支持子查詢.
e.高級(jí)特性
JPA中能夠支持面向?qū)ο蟮母呒?jí)特性,如類之間的集成,多態(tài)和類之間的復(fù)雜關(guān)系,這樣的支持能夠讓開發(fā)者最大限度的使用面向?qū)ο蟮哪P驮O(shè)計(jì)企業(yè)應(yīng)用,而不需要自行處理這些特性在關(guān)系數(shù)據(jù)庫(kù)的持久化
2 什么是SpringDataJpa
Spring Data JPA框架,主要針對(duì)的就是 Spring 唯一沒有簡(jiǎn)化到的業(yè)務(wù)邏輯代碼,至此,開發(fā)者連僅剩的實(shí)現(xiàn)持久層業(yè)務(wù)邏輯的工作都省了,唯一要做的,就只是聲明持久層的接口,其他都交給 Spring Data JPA 來(lái)幫你完成.
Spring data jpa是在JPA規(guī)范下提供了Repository層的實(shí)現(xiàn),但是使用哪一種ORM需要你來(lái)決定(默認(rèn)使用Hibernate JPA的實(shí)現(xiàn)).雖然ORM框架都實(shí)現(xiàn)了JPA規(guī)范,但是在不同的ORM框架之間切換仍然需要編寫不同的代碼,而通過使用Spring data jpa能夠方便大家在不同的ORM框架之間進(jìn)行切換而不要更改代碼.并且spring data jpa 對(duì)Repository層封裝的很好,也省去了不少的麻煩.
3 JPA入門
1.創(chuàng)建數(shù)據(jù)庫(kù)
2.創(chuàng)建項(xiàng)目|導(dǎo)入依賴
pom.xml
<properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.hibernate.version>5.0.7.Final</project.hibernate.version> <maven.compiler.source>1.9</maven.compiler.source> <maven.compiler.target>1.9</maven.compiler.target></properties><dependencies> <!-- junit --> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.12</version> <!--<scope>test</scope>--> </dependency> <!-- hibernate對(duì)jpa的支持包 --> <dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate-entitymanager</artifactId> <version>${project.hibernate.version}</version> </dependency> <!-- c3p0 --> <dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate-c3p0</artifactId> <version>${project.hibernate.version}</version> </dependency> <!-- log日志 --> <dependency> <groupId>log4j</groupId> <artifactId>log4j</artifactId> <version>1.2.17</version> </dependency> <!-- Mysql and MariaDB --> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.6</version> </dependency></dependencies>
3.配置文件
在src/main/resources/META-INF的文件夾下創(chuàng)建一個(gè)persistence.xml的配置文件.文件名不可改動(dòng)必須為persistence.xml.
<?xml version="1.0" encoding="UTF-8"?>
<persistence xmlns="http://java.sun.com/xml/ns/persistence" version="2.0">
name:持久化單元名稱
transaction-type:事務(wù)模式拍嵌。
RESOURCE_LOCAL:本地事務(wù)
JTA:分布式事務(wù)
-->
? ? <persistence-unit name="myJpa" transaction-type="RESOURCE_LOCAL">
? ? ? ? <provider>org.hibernate.jpa.HibernatePersistenceProvider</provider>
<properties>
? ? ? ? ? ? <property name="javax.persistence.jdbc.user" value="root"/>
<property name="javax.persistence.jdbc.password" value="root"/>
<property name="javax.persistence.jdbc.driver" value="com.mysql.jdbc.Driver"/>
<property name="javax.persistence.jdbc.url" value="jdbc:mysql://localhost:3306/jpa_test?characterEncoding=UTF-8"/>
? ? ? ? ? ? <property name="hibernate.show_sql" value="true"/>
? ? ? ? ? ? <property name="hibernate.format_sql" value="true"/>
可選值:create、create-drop,update、validate,none
create:程序自動(dòng)創(chuàng)建數(shù)據(jù)庫(kù)表,如果表存在則先刪除后創(chuàng)建. 測(cè)試環(huán)境使用
create-drop:程序自動(dòng)創(chuàng)建數(shù)據(jù)庫(kù)表虏冻,如果表存在則先刪除后創(chuàng)建. 程序結(jié)束時(shí)會(huì)刪除所有表結(jié)構(gòu).測(cè)試環(huán)境使用
update:程序自動(dòng)創(chuàng)建數(shù)據(jù)庫(kù)表呼寸,如果表存在則不創(chuàng)建。表與映射配置如果不一致,自動(dòng)修改表結(jié)構(gòu).測(cè)試環(huán)境使用
validate: 自動(dòng)校驗(yàn)表結(jié)構(gòu).既不會(huì)創(chuàng)建表,也不會(huì)修改表結(jié)構(gòu)
none:不會(huì)創(chuàng)建表,也不會(huì)修改/校驗(yàn)表
-->
? ? ? ? ? ? <property name="hibernate.hbm2ddl.auto" value="update"/>
</properties>
</persistence-unit>
</persistence>
4.創(chuàng)建實(shí)體類|映射
package cn.abc.pojo;
import? javax.persistence.*;
@Entity
@Table(name ="cst_customer")
public class Customer {
@Id
? ? @GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name ="cust_id")
private long custId;
@Column(name="cust_name")
private StringcustName;
@Column(name="cust_source")
private StringcustSource;
@Column(name="cust_industry")
private StringcustIndustry;
@Column(name="cust_level")
private StringcustLevel;
@Column(name="cust_address")
private StringcustAddress;
@Column(name="cust_phone")
private StringcustPhone;
public long getCustId() {
return custId;
}
public void setCustId(long custId) {
this.custId = custId;
}
public String getCustName() {
return custName;
}
public void setCustName(String custName) {
this.custName = custName;
}
public String getCustSource() {
return custSource;
}
public void setCustSource(String custSource) {
this.custSource = custSource;
}
public String getCustIndustry() {
return custIndustry;
}
public void setCustIndustry(String custIndustry) {
this.custIndustry = custIndustry;
}
public String getCustLevel() {
return custLevel;
}
public void setCustLevel(String custLevel) {
this.custLevel = custLevel;
}
public String getCustAddress() {
return custAddress;
}
public void setCustAddress(String custAddress) {
this.custAddress = custAddress;
}
public String getCustPhone() {
return custPhone;
}
public void setCustPhone(String custPhone) {
this.custPhone = custPhone;
}
}
5.書寫測(cè)試代碼
import cn.abc.pojo.Customer;
import org.junit.Test;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.EntityTransaction;
import javax.persistence.Persistence;
public class CustomerTest {
@Test
? ? public void testAddCustomer()throws Exception {
EntityManagerFactory factory = Persistence.createEntityManagerFactory("myJpa");
EntityManager entityManager = factory.createEntityManager();
EntityTransaction transaction = entityManager.getTransaction();
transaction.begin();
Customer customer =new Customer();
customer.setCustName("悔創(chuàng)阿里杰克馬");
entityManager.persist(customer);
transaction.commit();
//transaction.rollback();
? ? ? ? entityManager.close();
factory.close();
}
}
建表成功:
4 配置詳解
? ? 4.1 persistence.xml
<?xml version="1.0" encoding="UTF-8"?>
<persistence xmlns="http://java.sun.com/xml/ns/persistence" version="2.0">
? ? <!-- persistence-unit : 持久化單元配置.封裝了整套數(shù)據(jù)庫(kù)配置信息.該元素可以配置多個(gè)
? ? ? ? name:持久化單元名稱
? ? ? ? transaction-type:事務(wù)模式州袒。
? ? ? ? ? ? RESOURCE_LOCAL:本地事務(wù)
? ? ? ? ? ? JTA:分布式事務(wù)
? ? -->
? ? <persistence-unit name="myJpa" transaction-type="RESOURCE_LOCAL">
? ? ? ? <!--配置JPA提供商,默認(rèn)就是Hibernate -->
? ? ? ? <provider>org.hibernate.jpa.HibernatePersistenceProvider</provider>
? ? ? ? <properties>
? ? ? ? ? ? <!--連接數(shù)據(jù)庫(kù)配置-->
? ? ? ? ? ? <property name="javax.persistence.jdbc.user" value="root"/>
? ? ? ? ? ? <property name="javax.persistence.jdbc.password" value="root"/>
? ? ? ? ? ? <property name="javax.persistence.jdbc.driver" value="com.mysql.jdbc.Driver"/>
? ? ? ? ? ? <property name="javax.persistence.jdbc.url" value="jdbc:mysql://localhost:3306/jpa_test?characterEncoding=UTF-8"/>
? ? ? ? ? ? <!--jpa實(shí)現(xiàn)方的配置-->
? ? ? ? ? ? <!--是否打印sql語(yǔ)句-->
? ? ? ? ? ? <property name="hibernate.show_sql" value="true"/>
? ? ? ? ? ? <!--是否格式化sql語(yǔ)句-->
? ? ? ? ? ? <property name="hibernate.format_sql" value="true"/>
? ? ? ? ? ? <!--自動(dòng)建表策略
? ? ? ? ? ? ? ? 可選值:create看尼、create-drop,update猿诸、validate,none
? ? ? ? ? ? ? ? create:程序自動(dòng)創(chuàng)建數(shù)據(jù)庫(kù)表,如果表存在則先刪除后創(chuàng)建. 測(cè)試環(huán)境使用
? ? ? ? ? ? ? ? create-drop:程序自動(dòng)創(chuàng)建數(shù)據(jù)庫(kù)表狡忙,如果表存在則先刪除后創(chuàng)建. 程序結(jié)束時(shí)會(huì)刪除所有表結(jié)構(gòu).測(cè)試環(huán)境使用
? ? ? ? ? ? ? ? update:程序自動(dòng)創(chuàng)建數(shù)據(jù)庫(kù)表,如果表存在則不創(chuàng)建址芯。表與映射配置如果不一致,自動(dòng)修改表結(jié)構(gòu).測(cè)試環(huán)境使用
? ? ? ? ? ? ? ? validate: 自動(dòng)校驗(yàn)表結(jié)構(gòu).既不會(huì)創(chuàng)建表,也不會(huì)修改表結(jié)構(gòu)
? ? ? ? ? ? ? ? none:不會(huì)創(chuàng)建表,也不會(huì)修改/校驗(yàn)表
? ? ? ? ? ? -->
? ? ? ? ? ? <property name="hibernate.hbm2ddl.auto" value="none"/>
? ? ? ? </properties>
? ? </persistence-unit>
</persistence>
4.2 實(shí)體映射注解????
4.2.1 @Entity
? ?
4.2.2 @Table
4.2.3 @Id
4.2.4 @Column
4.2.5 @GeneratedValue
5. API詳解
5.1 Persistence
Persistence對(duì)象主要作用是用于獲取EntityManagerFactory對(duì)象的.通過調(diào)用該類的createEntityManagerFactory靜態(tài)方法,根據(jù)配置文件中持久化單元名稱創(chuàng)建EntityManagerFactory.
/** 詳解Persistence對(duì)象* 功能:* 1.讀取配置文件* 2.創(chuàng)建EntityManagerFactory**/
public class PersistenceDemo {
@Test
public void fun1(){
//讀取配置文件并創(chuàng)建
EntityManagerFactory EntityManagerFactory abc = Persistence.createEntityManagerFactory("abc");
}
}
5.2 EntityManagerFactory
EntityManagerFactory接口主要用來(lái)創(chuàng)建EntityManager實(shí)例
/* * 詳解EntityManagerFactory對(duì)象
????功能:
????創(chuàng)建EntityManager
注意:? 1.該對(duì)象消耗內(nèi)存資源較大
????????????2.該對(duì)象線程安全
結(jié)論:? 要確保在項(xiàng)目中,EntityManagerFactory只創(chuàng)建一個(gè)實(shí)例
*/
public class EntityManagerFactory {
@Test
public void fun(){
//讀取配置文件并創(chuàng)建
EntityManagerFactory javax.persistence.EntityManagerFactory factory = Persistence.createEntityManagerFactory("abc");
//創(chuàng)建EntityManager EntityManager entityManager = factory.createEntityManager();
????}
}
5.3 EntityManager
在JPA規(guī)范中,EntityManager是完成持久化操作的核心對(duì)象.實(shí)體類作為普通java對(duì)象,只有在調(diào)用EntityManager將其持久化后才會(huì)變成持久化對(duì)象.EntityManager對(duì)象在一組實(shí)體類與底層數(shù)據(jù)源之間進(jìn)行O/R 映射的管理.它可以用來(lái)管理和更新Entity Bean,根據(jù)主鍵查找Entity Bean,還可以通過JPQL語(yǔ)句查詢實(shí)體.
我們可以通過調(diào)用EntityManager的方法完成獲取事務(wù),以及持久化數(shù)據(jù)庫(kù)的操作
5.3.1 基礎(chǔ)增刪改查
????5.3.1.1 增
Customer c =? new Customer();
c.setCustName("不識(shí)美人劉強(qiáng)東");
entityManager .persist(c);
5.3.1.2 查
????5.3.1.2.1查(立即加載)
//查詢主鍵值為1L的Customer對(duì)象
//ps:主鍵由于pojo類的Id屬性為long類型且建表時(shí)默認(rèn)最大長(zhǎng)度 故填入long類型
Customer c =entityManager.find(Customer.class,1L);
System.out.pringln("==========");
System.out.pringln(c);?
????5.3.1.2.2查(延遲加載)
//查詢主鍵值為1L的Customer對(duì)象
Customer c = entityManager.getReference(Customer.class,1L);
System.out.pringln(c)
總結(jié):二者查詢打印結(jié)果一直,區(qū)別在于執(zhí)行順序,立即加載的find方法執(zhí)行時(shí)會(huì)立即查詢數(shù)據(jù)庫(kù)
而延遲加載getReference方法在執(zhí)行時(shí)不會(huì)查詢數(shù)據(jù)庫(kù),使用查詢結(jié)果時(shí)才會(huì)查詢
????5.3.1.3 改
? ? ?5.3.1.3.1 先查后改(推薦)
//查詢主鍵值為1L的Customer對(duì)象
Customer c = manager.find(Customer.class,1L);
c.setCustName("家里最丑劉亦菲");
entityManager.merge(c); //修改
? ? 5.3.1.3.2 自己創(chuàng)建對(duì)象修改(注意屬性值丟失,盡量用上一個(gè))
Customer c = new Customer();
c.setCustId(1L);
c.setCustName("家里最丑劉亦菲");
entityManager.merge(c); //修改
5.3.1.4 刪
//查詢出對(duì)象
Customer c = entityManager.find(Customer.class,1L);
//刪除對(duì)象
manager.remove(c);
5.3.2 JPQL
?JPQL全稱 Java Persistence Query Language,基于首次在EJB2.0中引入的EJB查詢語(yǔ)言(EJBQL),Java持久化查詢語(yǔ)言(JPQL)是一種可移植的查詢語(yǔ)言,詣在以面向?qū)ο蟊磉_(dá)式語(yǔ)言的表達(dá)式,將SQL語(yǔ)法和簡(jiǎn)單查詢語(yǔ)義綁定在一起,使用這種語(yǔ)言編寫的查詢時(shí)可移植的,可以被編譯成所有主流數(shù)據(jù)庫(kù)服務(wù)器上的SQL.
其特征與原生SQL語(yǔ)句類似,并且完全面向?qū)ο?通過類名和屬性訪問,而不是表明和表的屬性
5.3.2.1 基礎(chǔ)查詢
//書寫JPQL語(yǔ)句
//String jpql = "select c from cn.abc.pojo.Customer.java c";
//String jpql = "select c from Customer c";
String jpql = "from Customer";
//ps:以上三種效果一致
//將JPQL語(yǔ)句封裝為查詢對(duì)象
Query query = entityManager.createQuery(jpql);
//查詢并返回結(jié)果
List<Customer> list = query.getResultList();
System.out.println(list);
5.3.2.2 分頁(yè)查詢
//書寫JPQL語(yǔ)句
String jpql = "from Customer";
//封裝到Query對(duì)象中
Query query = entityManager.createQuery(jpql);
//設(shè)置分頁(yè)參數(shù) limit ?,?
query.setFirstResult(0); //第一個(gè)問號(hào) 從第幾頁(yè)開始
query.setMaxResults(2); //第二個(gè)問號(hào) 每頁(yè)讀幾個(gè)
//執(zhí)行并獲得查詢結(jié)果
List<Customer> list = query.getResultList();
System.out.println(list);
5.3.2.3 條件查詢
? ? 5.3.2.3.1 問號(hào)占位符
//書寫JPQL語(yǔ)句
String jpql = "from Customer where custName like ?";
//封裝到Query對(duì)象中
Query query = entityManager.createQuery(jpql);
//指定占位符的值
query.setParameter(1,"%撒%");
//執(zhí)行并獲得查詢結(jié)果
List<Customer> list = query.getResultList();
System.out.println(list);
????5.3.2.3.2 命名占位符
//書寫JPQL語(yǔ)句
String jpql = "from Customer where custName like :hehe";
//封裝到Query對(duì)象中
Query query = entityManager.createQuery(jpql);
//指定占位符的值
query.setParameter("hehe","%撒%");
//執(zhí)行并獲得查詢結(jié)果
List<Customer> list = query.getResultList();
System.out.println(list);
5.3.2.4 排序
//書寫JPQL語(yǔ)句
String jpql = "from Customer order by custId desc";
//封裝到Query對(duì)象中
Query query = entityManager.createQuery(jpql);
//執(zhí)行并獲得查詢結(jié)果
List<Customer> list = query.getResultList();
System.out.println(list);
5.3.2.5 聚合函數(shù)
//書寫JPQL語(yǔ)句
String jpql1 = "select count(c) from Customer c ";
String jpql2 = "select sum(c.custId) from Customer";
String jpql3 = "select avg(c.custId) from Customer";
String jpql4 = "select max(c.custId) from Customer";
String jpql5 = "select min(c.custId) from Customer";
//封裝到Query對(duì)象中
Query query = entityManager.createQuery(jpql5);
//執(zhí)行并獲得查詢結(jié)果
Number num = (Number) query.getSingleResult();
System.out.println(num);
5.3.3 EntityTransaction
/*? 詳解EntityTransaction對(duì)象?
功能:?
????事務(wù)管理對(duì)象,用于管理事務(wù)?
????事務(wù)開啟/提交/回滾...?
*/
//讀取配置文件并創(chuàng)建
EntityManagerFactoryjavax.persistence.EntityManagerFactory factory = Persistence.createEntityManagerFactory("myJpa");
//創(chuàng)建EntityManager
EntityManager entityManager = factory.createEntityManager();
System.out.println("-----------以下為transaction對(duì)象-------------");
//獲得Transaction對(duì)象
EntityTransaction transaction = entityManager.getTransaction();
transaction.begin();//開啟事務(wù)
transaction.commit();//提交事務(wù)
transaction.rollback();//回滾事務(wù)