原文發佈於:http://www.gufeng.tech/ 穀風的我的主頁java
JPA全稱Java Persistence API即Java持久化API,是一種經過註解或者XML配置描述映射關係來實現將實體持久化到數據庫的一種java持久化實現方案。JPA和JDBC同樣,都是jdk提供的API,各廠商提供實現,目前的實現有Apache的OpenJPA以及應用普遍的Hibernate,固然還有其它的實現,這裏就不一一列出了。JAP做爲一種標準,已經得到了JavaEES容器的支持,同時也仍然能夠在JavaSE環境中使用,這就奠基了它可被普遍應用的前提。mysql
JPA在隨着SpringBoot的默認支持,再次被普遍說起、應用。做爲一種ORM的技術,除了擁有ORM的特色以外,還有一些它本身的特色:程序員
1 標準化web
JPA是java標準化組織JCP提出的一項持久化標準,因此其任何實現都提供了相同的API,即使更換了實現方案,兼容性也是很是好的。sql
2 更面向對象數據庫
JPA支持面向對象中的繼承、多態及多個類間的關聯關係,所以使得程序員在使用JPA開發時能夠方便的使用面向對象的思惟,過渡性比較好。併發
3 功能全面框架
JPA支持事務、併發等特性,而不只僅是一個簡單的持久化框架,於是能夠在實際使用中發揮更大的做用。ide
4 卓越的查詢能力工具
JPA是面向對象的,定義了JPQL(Java Persistence Query Language),JPQL是一種針對實體的查詢語句,操做對象是實體,能夠以面向對象的方式構造查詢語句,在這點上相似Hibernate的HQL。JPQL可以支持批量操做(如更新和修改)、join、group by、having等子句,同時還支持子查詢,所以其查詢能力可見一斑。
5 集成方便
這一點從SpringBoot選擇了JPA就可以看出來。在JPA框架下建立實體只須要使用javax.persistence.Entity註解便可,其接口使用也很是簡單容易上手,尤爲重要的一點是JPA被設計成非***式的,自然註定了它可以被很是容易的集成。
JPA涉及的技術
1 元數據
關於映射關係,JPA同時支持註解和XML。
2 API
操做簡單,將程序員從繁瑣的SQL中解放出來。
3 查詢語言
經過面向對象的方式進行數據查詢,避免程序與SQL語句的的耦合。
上面說起了JPA的各類好處,那麼做爲一種技術方案(或者叫規範),JPA有沒有缺點呢?答案是確定的,JPA將數據庫關係以實體及實體間關係表示,必然存在一種將數據庫的複雜概念(如一對1、一對多、多對多等關係)轉移到程序中。這會帶來如下一些問題:
1 程序可讀性差,若是遇到特別複雜的業務邏輯,那麼對於實體的定義也會很是困難,這須要設計者具備很是高的抽象、規範、設計能力。
2 數據關係發生變化時,實體必然也會發生變化。
3 將關係型數據庫映射到面向對象程序上,自己就有着深度的複雜性,二者關注點不一樣,當關聯到一塊兒的時候必然會來帶衝突。數據庫關心的是數據以及數據的完整性;面向對象關心的是對象的成員及行爲。
接下來介紹下JPA的一些核心類:
1 EntityManagerFactory
EntityManagerFactory 是 EntityManager 的工廠類,負責建立 EntityManager 對象。
2 EntityManager
EntityManager 是 JPA 應用中使用的基本對象,經過它提供的相應方法能夠管理持久化對象,也能夠新建或者刪除持久化對象。EntityManager 還負責建立 Query 實例。在容器外使用時,EntityManagerFactory 和 EntityManager 之間是一對一的關係。
3 EntityTransaction
EntityTransaction 提供 Entity 操做時須要的事務管理,和 EntityManager 是一對一的關係。在查詢操做時不須要使用 EntityTransaction,而在對象持久化、狀態更新、對象刪除等狀況下則必須使用顯式的使用 EntityTransaction 的相關方法管理事務。
4 Query
Query 是查詢實體的接口,Query 對象能夠從 EntityManager 中得到。根據 EJB 3.0 規範中的描述,Query 接口須要同時支持 JPQL 和原生態 SQL 兩種語法。
5 Persistence
Persistence 是一個工具類,負責根據配置文件提供的參數建立 EntityManagerFactory 對象。
最後看一段JPA的示例代碼:
import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.Id; import javax.persistence.Table; @Entity @Table(name = "user") public class User { @Id @Column(name = "id") private String id; @Column(name = "name") private String name; public String getId() { return id; } public void setId(String id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } }
import javax.persistence.EntityManager; import javax.persistence.EntityManagerFactory; import javax.persistence.Persistence; import java.util.List; public class Main { static EntityManagerFactory emf = Persistence.createEntityManagerFactory("gufengJPA"); static EntityManager em = emf.createEntityManager(); public static void main(String[] args) { User person = new User(); person.setId(123456l); person.setName("張無忌"); em.persist(person); add(person); System.out.println("user id:" + person.getId()); User user = find(person.getId()); System.out.println(user); List<User> all = findAll(); for (User u : all) { System.out.println(u); } em.close(); emf.close(); } public static void add(User user) { em.getTransaction().begin(); em.persist(user); em.getTransaction().commit(); } public static User find(Object id) { User user = em.find(User.class, id); return user; } public static List<User> findAll() { List<User> users = em.createQuery("select u from User u") .getResultList(); return users; } }
<?xml version="1.0" encoding="UTF-8"?> <persistence version="2.0" xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd"> <!-- 持久化單元 --> <persistence-unit name="gufengJPA" transaction-type="RESOURCE_LOCAL"> <!--能夠指定,若是不指定則從META-INF/services加載--> <!--<provider>org.hibernate.jpa.HibernatePersistenceProvider</provider>--> <!-- <class>com.micmiu.hibernate.jpa.UserInfo</class> --> <!--<provider>com.tongweb.openjpa.persistence.PersistenceProviderImpl</provider>--> <!--<jta-data-source>MyDataSource</jta-data-source>--> <!-- class 定義指定持久化的實體類 注意配置屬性hibernate.archive.autodetection=false --> <!--<class>jpa.User</class>--> <properties> <property name="hibernate.archive.autodetection" value="class,hbm"/> <!--Hibernate 方言 --> <property name="hibernate.dialect" value="org.hibernate.dialect.MySQL5InnoDBDialect"/> <!--數據庫url --> <property name="hibernate.connection.url" value="jdbc:mysql://localhost:3306/test"/> <!--數據庫驅動 --> <property name="hibernate.connection.driver_class" value="com.mysql.jdbc.Driver"/> <!--配置數據庫用戶名 --> <property name="hibernate.connection.username" value="root"/> <!--配置數據庫密碼 --> <property name="hibernate.connection.password" value="123456"/> <!--設置外鏈接抓取樹的最大深度 --> <!--<property name="hibernate.max_fetch_depth" value="3"/>--> <!--自動輸出schema建立DDL語句 --> <!--<property name="hibernate.hbm2ddl.auto" value="update"/>--> <property name="hibernate.show_sql" value="true"/> </properties> </persistence-unit> </persistence>
這裏須要注意的是JPA配置文件persistence.xml 必需放到類路徑的根路徑的META-INF文件夾下。
Persistence.createEntityManagerFactory("gufengJPA");
上面這行代碼是經過Java的SPI機制得到具體實現的。在hibernate的jar包裏有個META-INF/services/javax.persistence.spi.PersistenceProvider 文件,這裏指定的實現爲 org.hibernate.jpa.HibernatePersistenceProvider。再有多個的時候,Persistence只會使用第一個。