全稱Java Persistence API,經過JDK 5.0註解或XML描述對象-關係表的映射關係,並將運行期的實體對象持久化到數據庫中。java
一、JPA和Hibernate的關係數據庫
簡而言之編程
JPA 是一個規範或者接口框架
Hibernate 是 JPA 的一個實現ide
JPA與Hibernate的關係相似於JDBC和JDBC驅動的關係,是對生產力的一種解放。咱們不需定製符合供應商提供的API,只需符合規範便可保證它的遷移性。工具
JPA 是規範:JPA 本質上就是一種 ORM 規範,不是ORM 框架 —— 由於 JPA 並未提供 ORM 實現,它只是制訂了一些規範,提供了一些編程的 API 接口,但具體實現則由 ORM 廠商提供實現性能
Hibernate 是實現,是一種ORM產品:Hibernate 除了做爲 ORM 框架以外,它也是一種 JPA 實現fetch
從功能上來講, JPA 是 Hibernate 功能的一個子集this
JPA 的目標之一是制定一個能夠由不少供應商實現的 API,目前Hibernate 3.2+、TopLink 10.1+ 以及 OpenJPA 都提供了 JPA 的實現spa
Hibernate:JPA 的始做俑者就是 Hibernate 的做者。Hibernate 從 3.2 開始兼容 JPA
OpenJPA:OpenJPA 是 Apache 組織提供的開源項目
TopLink:TopLink 之前須要收費,現在開源了
JPA的出現有兩個緣由:
其一,簡化現有Java EE和Java SE應用的對象持久化的開發工做;
其二,Sun但願整合對ORM技術,實現持久化領域的統一。
1)ORM映射元數據:JPA支持XML和JDK 5.0註解兩種元數據的形式,元數據描述對象和表之間的映射關係,框架據此將實體對象持久化到數據庫表中;
2)JPA 的API:用來操做實體對象,執行CRUD操做,框架在後臺替咱們完成全部的事情,開發者從繁瑣的JDBC和SQL代碼中解脫出來。
3)查詢語言:經過面向對象而非面向數據庫的查詢語言查詢數據,避免程序的SQL語句緊密耦合。
JPA 基本註解:@Entity, @Table, @Id, @GeneratedValue, @Column, @Basic,@Transient, @Temporal
@Entity 標註用於實體類聲明語句以前,指出該Java 類爲實體類,將映射到指定的數據庫表。如聲明一個實體類 Customer,它將映射到數據庫中的 customer 表上。
當實體類與其映射的數據庫表名不一樣名時須要使用 @Table 標註說明,該標註與 @Entity 標註並列使用,置於實體類聲明語句以前,可寫於單獨語句行,也可與聲明語句同行。
@Table 標註的經常使用選項是 name,用於指明數據庫的表名
@Table標註還有一個兩個選項 catalog 和 schema 用於設置表所屬的數據庫目錄或模式,一般爲數據庫名。uniqueConstraints 選項用於設置約束條件,一般不須設置。
@Id 標註用於聲明一個實體類的屬性映射爲數據庫的主鍵列。該屬性一般置於屬性聲明語句以前,可與聲明語句同行,也可寫在單獨行上。
@Id標註也可置於屬性的getter方法以前。
@GeneratedValue 用於標註主鍵的生成策略,經過 strategy 屬性指定。默認狀況下,JPA 自動選擇一個最適合底層數據庫的主鍵生成策略:SqlServer 對應 identity,
MySQL 對應 auto increment。在 javax.persistence.GenerationType 中定義瞭如下幾種可供選擇的策略:
IDENTITY:採用數據庫 ID自增加的方式來自增主鍵字段,Oracle 不支持這種方式;
AUTO: JPA自動選擇合適的策略,是默認選項;
SEQUENCE:經過序列產生主鍵,經過 @SequenceGenerator 註解指定序列名,MySql 不支持這種方式
TABLE:經過表產生主鍵,框架藉由表模擬序列產生主鍵,使用該策略可使應用更易於數據庫移植。
@Basic 表示一個簡單的屬性到數據庫表的字段的映射,對於沒有任何標註的 getXxxx() 方法,默認即爲@Basic
fetch: 表示該屬性的讀取策略,有 EAGER 和 LAZY 兩種,分別表示主支抓取和延遲加載,默認爲 EAGER.
optional:表示該屬性是否容許爲null, 默認爲true
當實體的屬性與其映射的數據庫表的列不一樣名時須要使用@Column 標註說明,該屬性一般置於實體的屬性聲明語句以前,還可與 @Id 標註一塊兒使用。
@Column 標註的經常使用屬性是 name,用於設置映射數據庫表的列名。此外,該標註還包含其它多個屬性,如:unique 、nullable、length等。
@Column 標註的 columnDefinition 屬性: 表示該字段在數據庫中的實際類型.一般 ORM 框架能夠根據屬性類型自動判斷數據庫中字段的類型,
可是對於Date類型仍沒法肯定數據庫中字段類型到底是DATE,TIME仍是TIMESTAMP.此外,String的默認映射類型爲VARCHAR,
若是要將 String 類型映射到特定數據庫的 BLOB 或TEXT 字段類型.
@Column標註也可置於屬性的getter方法以前
表示該屬性並不是一個到數據庫表的字段的映射,ORM框架將忽略該屬性.
若是一個屬性並不是數據庫表的字段映射,就務必將其標示爲@Transient,不然,ORM框架默認其註解爲@Basic
在覈心的 Java API 中並無定義 Date 類型的精度(temporal precision). 而在數據庫中,表示 Date 類型的數據有 DATE, TIME, 和 TIMESTAMP 三種精度
(即單純的日期,時間,或者二者 兼備).在進行屬性映射時可以使用@Temporal註解來調整精度.
將當前主鍵的值單獨保存到一個數據庫的表中,主鍵的值每次都是從指定的表中查詢來得到
這種方法生成主鍵的策略能夠適用於任何數據庫,沒必要擔憂不一樣數據庫不兼容形成的問題。
/** * 註解@Entity映射的表名和類名同樣 * 註解@Table:當實體類與其映射的數據庫表名不一樣名時使用。其中name,用於指明數據庫的表名 */ @Table(name="JPA_CUTOMER") @Entity public class Customer { private Integer id; private String name; private String email; private int age; private Date createTime; private Date birth; public Customer() {} //用 table 來生成主鍵詳解(用的少): //將當前主鍵的值單獨保存到一個數據庫的表中,主鍵的值每次都是從指定的表中查詢來得到 //這種方法生成主鍵的策略能夠適用於任何數據庫,沒必要擔憂不一樣數據庫不兼容形成的問題 /* @TableGenerator(name="ID_GENERATOR", --name 屬性表示該主鍵生成的名稱,它被引用在@GeneratedValue中設置的generator 值中(即這兩個名字要同樣) table="jpa_id_generators", --table 屬性表示表生成策略所持久化的表名 pkColumnName="PK_NAME", --pkColumnName 屬性的值表示在持久化表中,該主鍵生成策略所對應鍵值的名稱 pkColumnValue="CUSTOMER_ID", --pkColumnValue 屬性的值表示在持久化表中,該生成策略所對應的主鍵(跟pkColumnName屬性能夠肯定惟一的一行,該行有不少列) valueColumnName="PK_VALUE", --valueColumnName 屬性的值表示在持久化表中,該主鍵當前所生成的值,它的值將會隨着每次建立累加,(再加這個屬性能肯定惟一的那個點) allocationSize=100) --allocationSize 表示每次主鍵值增長的大小, 默認值爲 50 @GeneratedValue(strategy=GenerationType.TABLE,generator="ID_GENERATOR")*/ @GeneratedValue(strategy=GenerationType.AUTO) @Id public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } /** * 註解@Column 當實體的屬性與其映射的數據庫表的列不一樣名時須要使用 * nullable=false不能爲空 */ @Column(name="NAME",length=50,nullable=false) public String getName() { return name; } public void setName(String name) { this.name = name; } //若是 列名跟字段同樣如列名是email,則能夠不用寫,相關加了@Basic,但字段的屬性都是默認的 // @Basic public String getEmail() { return email; } public void setEmail(String email) { this.email = email; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } //--------------------------------------------------------------- //註解@Temporal 調整時間精度 2018-11-11 10:11:11 @Temporal(TemporalType.TIMESTAMP) public Date getCreateTime() { return createTime; } public void setCreateTime(Date createTime) { this.createTime = createTime; } //2018-11-11 @Temporal(TemporalType.DATE) public Date getBirth() { return birth; } public void setBirth(Date birth) { this.birth = birth; } //工具方法. 不須要映射爲數據表的一列. 若是沒有加@Transient,則會出錯,由於沒有set方法 @Transient public String getInfo(){ return "name: " + name + ", email: " + email; } }