Spring Data JPA 梳理 - JPA是什麼
總結:
- JPA是java的標準,不是Spring的標準
- java標準中一般通過Meta-INF檔案規範開發層面的事情,JPA也不例外,使用persistence.xml
- JPA定義了Entity 到 DB 雙向對映的一些標準,以及Entity操作DB的API規範
- JPA也定義了Entity 自動生成 DB Table 的規範
- JPA其實也就是java實體物件和關係型資料庫建立起對映關係,通過面向物件程式設計的思想操作關係型資料庫的規範。
本文最新版已更新至:http://thinkinside.tk/2012/12/30/JPA.html
JPA定義了Java ORM及實體操作API的標準。本文摘錄了JPA的一些關鍵資訊以備查閱。
如果有hibernate的基礎,通過本文也可以快速掌握JPA的基本概念及使用。
Table of Contents
1 JPA概述
JPA(Java Persistence API,Java持久化API),定義了物件-關係對映(ORM)以及實體物件持久化的標準介面。
JPA是JSR-220(EJB3.0)規範的一部分,在JSR-220中規定實體物件(EntityBean)由JPA進行支援。
所以JPA不侷限於EJB3.0,而是作為POJO持久化的標準規範,可以脫離容器獨立執行,開發和測試更加方便。
JPA在應用中的位置如下圖所示:
JPA維護一個Persistence Context(持久化上下文),在持久化上下文中維護實體的生命週期。主要包含三個方面的內容:
- ORM元資料。JPA支援annotion或xml兩種形式描述物件-關係對映。
- 實體操作API。實現對實體物件的CRUD操作。
- 查詢語言。約定了面向物件的查詢語言JPQL(Java Persistence Query Language)。
JPA的主要API都定義在javax.persistence包中。如果你熟悉Hibernate,可以很容易做出對應:
org.hibernate | javax.persistence | 說明 |
---|---|---|
cfg.Configuration | Persistence | 讀取配置資訊 |
SessionFactory | EntityManagerFactory | 用於建立會話/實體管理器的工廠類 |
Session | EntityManager | 提供實體操作API,管理事務,建立查詢 |
Transaction | EntityTransaction | 管理事務 |
Query | Query | 執行查詢 |
2 實體生命週期
實體生命週期是JPA中非常重要的概念,描述了實體物件從建立到受控、從刪除到遊離的狀態變換。對實體的操作主要就是改變實體的狀態。
JPA中實體的生命週期如下圖:
- New,新建立的實體物件,沒有主鍵(identity)值
- Managed,物件處於Persistence Context(持久化上下文)中,被EntityManager管理
- Detached,物件已經遊離到Persistence Context之外,進入Application Domain
- Removed, 實體物件被刪除
EntityManager提供一系列的方法管理實體物件的生命週期,包括:
- persist, 將新建立的或已刪除的實體轉變為Managed狀態,資料存入資料庫。
- remove,刪除受控實體
- merge,將遊離實體轉變為Managed狀態,資料存入資料庫。
如果使用了事務管理,則事務的commit/rollback也會改變實體的狀態。
3 實體關係對映(ORM)
3.1 基本對映
物件端 | 資料庫端 | annotion | 可選annotion |
---|---|---|---|
Class | Table | @Entity | @Table(name="tablename") |
property | column | – | @Column(name = "columnname") |
property | primary key | @Id | @GeneratedValue 詳見ID生成策略 |
property | NONE | @Transient |
3.2 ID生成策略
ID對應資料庫表的主鍵,是保證唯一性的重要屬性。JPA提供了以下幾種ID生成策略
- GeneratorType.AUTO ,由JPA自動生成
- GenerationType.IDENTITY,使用資料庫的自增長欄位,需要資料庫的支援(如SQL Server、MySQL、DB2、Derby等)
- GenerationType.SEQUENCE,使用資料庫的序列號,需要資料庫的支援(如Oracle)
- GenerationType.TABLE,使用指定的資料庫表記錄ID的增長 需要定義一個TableGenerator,在@GeneratedValue中引用。例如:
@TableGenerator( name="myGenerator", table="GENERATORTABLE", pkColumnName = "ENTITYNAME", pkColumnValue="MyEntity", valueColumnName = "PKVALUE", allocationSize=1 )
@GeneratedValue(strategy = GenerationType.TABLE,generator="myGenerator")
3.3 關聯關係
JPA定義了one-to-one、one-to-many、many-to-one、many-to-many 4種關係。
對於資料庫來說,通常在一個表中記錄對另一個表的外來鍵關聯;對應到實體物件,持有關聯資料的一方稱為owning-side,另一方稱為inverse-side。
為了程式設計的方便,我們經常會希望在inverse-side也能引用到owning-side的物件,此時就構建了雙向關聯關係。 在雙向關聯中,需要在inverse-side定義mappedBy屬性,以指明在owning-side是哪一個屬性持有的關聯資料。
對關聯關係對映的要點如下:
關係型別 | Owning-Side | Inverse-Side |
---|---|---|
one-to-one | @OneToOne | @OneToOne(mappedBy="othersideName") |
one-to-many / many-to-one | @ManyToOne | @OneToMany(mappedBy="xxx") |
many-to-many | @ManyToMany | @ManyToMany(mappedBy ="xxx") |
其中 many-to-many關係的owning-side可以使用@JoinTable宣告自定義關聯表,比如Book和Author之間的關聯表:
@JoinTable(name = "BOOKAUTHOR", joinColumns = { @JoinColumn(name = "BOOKID", referencedColumnName = "id") }, inverseJoinColumns = { @JoinColumn(name = "AUTHORID", referencedColumnName = "id") })
關聯關係還可以定製延遲載入和級聯操作的行為(owning-side和inverse-side可以分別設定):
通過設定fetch=FetchType.LAZY 或 fetch=FetchType.EAGER來決定關聯物件是延遲載入或立即載入。
通過設定cascade={options}可以設定級聯操作的行為,其中options可以是以下組合:
- CascadeType.MERGE 級聯更新
- CascadeType.PERSIST 級聯儲存
- CascadeType.REFRESH 級聯重新整理
- CascadeType.REMOVE 級聯刪除
- CascadeType.ALL 級聯上述4種操作
3.4 繼承關係
JPA通過在父類增加@Inheritance(strategy=InheritanceType.xxx)來宣告繼承關係。A支援3種繼承策略:
- 單表繼承(InheritanceType.SINGLETABLE),所有繼承樹上的類共用一張表,在父類指定(@DiscriminatorColumn)宣告並在每個類指定@DiscriminatorValue來區分型別。
- 類表繼承(InheritanceType.JOINED),父子類共同的部分公用一張表,其餘部分儲存到各自的表,通過join進行關聯。
- 具體表繼承(InheritanceType.TABLEPERCLASS),每個具體類對映到自己的表。
其中1和2能夠支援多型,但是1需要允許欄位為NULL,2需要多個JOIN關係;3最適合關係資料庫,對多型支援不好。具體應用時根據需要取捨。
4 事件及監聽
通過在實體的方法上標註@PrePersist,@PostPersist等宣告即可在事件發生時觸發這些方法。
5 Query Language 查詢語言
JPA提供兩種查詢方式,一種是根據主鍵查詢,使用EntityManager的find方法:
T find(Class entityClass, Object primaryKey)
另一種就是使用JPQL查詢語言。JPQL是完全面向物件的,具備繼承、多型和關聯等特性,和hibernate HQL很相似。
使用EntityManager的createQuery方法:
Query createQuery(String qlString)
5.1 使用引數
可以在JPQL語句中使用引數。JPQL支援命名引數和位置引數兩種引數,但是在一條JPQL語句中所有的引數只能使用同一種類型。
舉例如下:
- 命令引數
Query query = em.createQuery("select p from Person p where p.personid=:Id"); query.setParameter("Id",new Integer(1));
- 位置引數
Query query = em.createQuery("select p from Person p where p.personid=?1"); query.setParameter(1,new Integer(1));
5.2 命名查詢
如果某個JPQL語句需要在多個地方使用,還可以使用@NamedQuery 或者 @NamedQueries在實體物件上預定義命名查詢。
在需要呼叫的地方只要引用該查詢的名字即可。
例如:
@NamedQuery(name="getPerson", query= "FROM Person WHERE personid=?1")
@NamedQueries({ @NamedQuery(name="getPerson1", query= "FROM Person WHERE personid=?1"), @NamedQuery(name="getPersonList", query= "FROM Person WHERE age>?1") })
Query query = em.createNamedQuery("getPerson");
5.3 排序
JPQL也支援排序,類似於SQL中的語法。例如: Query query = em.createQuery("select p from Person p order by p.age, p.birthday desc");
5.4 聚合查詢
JPQL支援AVG、SUM、COUNT、MAX、MIN五個聚合函式。例如:
Query query = em.createQuery("select max(p.age) from Person p"); Object result = query.getSingleResult(); String maxAge = result.toString();
5.5 更新和刪除
JPQL不僅用於查詢,還可以用於批量更新和刪除。
如:
Query query = em.createQuery("update Order as o set o.amount=o.amount+10"); //update 的記錄數 int result = query.executeUpdate();
Query query = em.createQuery("delete from OrderItem item where item.order in(from Order as o where o.amount<100)"); query.executeUpdate();
query = em.createQuery("delete from Order as o where o.amount<100"); query.executeUpdate();//delete的記錄數
5.6 更多
與SQL類似,JPQL還涉及到更多的語法,可以參考:http://docs.oracle.com/cd/E11035_01/kodo41/full/html/ejb3_langref.html
6 事務管理
JPA支援本地事務管理(RESOURCELOCAL)和容器事務管理(JTA),容器事務管理只能用在EJB/Web容器環境中。
事務管理的型別可以在persistence.xml檔案中的“transaction-type”元素配置。
JPA中通過EntityManager的getTransaction()方法獲取事務的例項(EntityTransaction),之後可以呼叫事務的begin()、commit()、rollback()方法。
Date: 2012-12-30 16:46:29 CST
Org version 7.8.11 with Emacs version 24
Validate XHTML 1.0 轉:https://www.cnblogs.com/holbrook/archive/2012/12/30/2839842.html本文最新版已更新至:http://thinkinside.tk/2012/12/30/JPA.html
JPA定義了Java ORM及實體操作API的標準。本文摘錄了JPA的一些關鍵資訊以備查閱。
如果有hibernate的基礎,通過本文也可以快速掌握JPA的基本概念及使用。
Table of Contents
1 JPA概述
JPA(Java Persistence API,Java持久化API),定義了物件-關係對映(ORM)以及實體物件持久化的標準介面。
JPA是JSR-220(EJB3.0)規範的一部分,在JSR-220中規定實體物件(EntityBean)由JPA進行支援。
所以JPA不侷限於EJB3.0,而是作為POJO持久化的標準規範,可以脫離容器獨立執行,開發和測試更加方便。
JPA在應用中的位置如下圖所示:
JPA維護一個Persistence Context(持久化上下文),在持久化上下文中維護實體的生命週期。主要包含三個方面的內容:
- ORM元資料。JPA支援annotion或xml兩種形式描述物件-關係對映。
- 實體操作API。實現對實體物件的CRUD操作。
- 查詢語言。約定了面向物件的查詢語言JPQL(Java Persistence Query Language)。
JPA的主要API都定義在javax.persistence包中。如果你熟悉Hibernate,可以很容易做出對應:
org.hibernate | javax.persistence | 說明 |
---|---|---|
cfg.Configuration | Persistence | 讀取配置資訊 |
SessionFactory | EntityManagerFactory | 用於建立會話/實體管理器的工廠類 |
Session | EntityManager | 提供實體操作API,管理事務,建立查詢 |
Transaction | EntityTransaction | 管理事務 |
Query | Query | 執行查詢 |
2 實體生命週期
實體生命週期是JPA中非常重要的概念,描述了實體物件從建立到受控、從刪除到遊離的狀態變換。對實體的操作主要就是改變實體的狀態。
JPA中實體的生命週期如下圖:
- New,新建立的實體物件,沒有主鍵(identity)值
- Managed,物件處於Persistence Context(持久化上下文)中,被EntityManager管理
- Detached,物件已經遊離到Persistence Context之外,進入Application Domain
- Removed, 實體物件被刪除
EntityManager提供一系列的方法管理實體物件的生命週期,包括:
- persist, 將新建立的或已刪除的實體轉變為Managed狀態,資料存入資料庫。
- remove,刪除受控實體
- merge,將遊離實體轉變為Managed狀態,資料存入資料庫。
如果使用了事務管理,則事務的commit/rollback也會改變實體的狀態。
3 實體關係對映(ORM)
3.1 基本對映
物件端 | 資料庫端 | annotion | 可選annotion |
---|---|---|---|
Class | Table | @Entity | @Table(name="tablename") |
property | column | – | @Column(name = "columnname") |
property | primary key | @Id | @GeneratedValue 詳見ID生成策略 |
property | NONE | @Transient |
3.2 ID生成策略
ID對應資料庫表的主鍵,是保證唯一性的重要屬性。JPA提供了以下幾種ID生成策略
- GeneratorType.AUTO ,由JPA自動生成
- GenerationType.IDENTITY,使用資料庫的自增長欄位,需要資料庫的支援(如SQL Server、MySQL、DB2、Derby等)
- GenerationType.SEQUENCE,使用資料庫的序列號,需要資料庫的支援(如Oracle)
- GenerationType.TABLE,使用指定的資料庫表記錄ID的增長 需要定義一個TableGenerator,在@GeneratedValue中引用。例如:
@TableGenerator( name="myGenerator", table="GENERATORTABLE", pkColumnName = "ENTITYNAME", pkColumnValue="MyEntity", valueColumnName = "PKVALUE", allocationSize=1 )
@GeneratedValue(strategy = GenerationType.TABLE,generator="myGenerator")
3.3 關聯關係
JPA定義了one-to-one、one-to-many、many-to-one、many-to-many 4種關係。
對於資料庫來說,通常在一個表中記錄對另一個表的外來鍵關聯;對應到實體物件,持有關聯資料的一方稱為owning-side,另一方稱為inverse-side。
為了程式設計的方便,我們經常會希望在inverse-side也能引用到owning-side的物件,此時就構建了雙向關聯關係。 在雙向關聯中,需要在inverse-side定義mappedBy屬性,以指明在owning-side是哪一個屬性持有的關聯資料。
對關聯關係對映的要點如下:
關係型別 | Owning-Side | Inverse-Side |
---|---|---|
one-to-one | @OneToOne | @OneToOne(mappedBy="othersideName") |
one-to-many / many-to-one | @ManyToOne | @OneToMany(mappedBy="xxx") |
many-to-many | @ManyToMany | @ManyToMany(mappedBy ="xxx") |
其中 many-to-many關係的owning-side可以使用@JoinTable宣告自定義關聯表,比如Book和Author之間的關聯表:
@JoinTable(name = "BOOKAUTHOR", joinColumns = { @JoinColumn(name = "BOOKID", referencedColumnName = "id") }, inverseJoinColumns = { @JoinColumn(name = "AUTHORID", referencedColumnName = "id") })
關聯關係還可以定製延遲載入和級聯操作的行為(owning-side和inverse-side可以分別設定):
通過設定fetch=FetchType.LAZY 或 fetch=FetchType.EAGER來決定關聯物件是延遲載入或立即載入。
通過設定cascade={options}可以設定級聯操作的行為,其中options可以是以下組合:
- CascadeType.MERGE 級聯更新
- CascadeType.PERSIST 級聯儲存
- CascadeType.REFRESH 級聯重新整理
- CascadeType.REMOVE 級聯刪除
- CascadeType.ALL 級聯上述4種操作
3.4 繼承關係
JPA通過在父類增加@Inheritance(strategy=InheritanceType.xxx)來宣告繼承關係。A支援3種繼承策略:
- 單表繼承(InheritanceType.SINGLETABLE),所有繼承樹上的類共用一張表,在父類指定(@DiscriminatorColumn)宣告並在每個類指定@DiscriminatorValue來區分型別。
- 類表繼承(InheritanceType.JOINED),父子類共同的部分公用一張表,其餘部分儲存到各自的表,通過join進行關聯。
- 具體表繼承(InheritanceType.TABLEPERCLASS),每個具體類對映到自己的表。
其中1和2能夠支援多型,但是1需要允許欄位為NULL,2需要多個JOIN關係;3最適合關係資料庫,對多型支援不好。具體應用時根據需要取捨。
4 事件及監聽
通過在實體的方法上標註@PrePersist,@PostPersist等宣告即可在事件發生時觸發這些方法。
5 Query Language 查詢語言
JPA提供兩種查詢方式,一種是根據主鍵查詢,使用EntityManager的find方法:
T find(Class entityClass, Object primaryKey)
另一種就是使用JPQL查詢語言。JPQL是完全面向物件的,具備繼承、多型和關聯等特性,和hibernate HQL很相似。
使用EntityManager的createQuery方法:
Query createQuery(String qlString)
5.1 使用引數
可以在JPQL語句中使用引數。JPQL支援命名引數和位置引數兩種引數,但是在一條JPQL語句中所有的引數只能使用同一種類型。
舉例如下:
- 命令引數
Query query = em.createQuery("select p from Person p where p.personid=:Id"); query.setParameter("Id",new Integer(1));
- 位置引數
Query query = em.createQuery("select p from Person p where p.personid=?1"); query.setParameter(1,new Integer(1));
5.2 命名查詢
如果某個JPQL語句需要在多個地方使用,還可以使用@NamedQuery 或者 @NamedQueries在實體物件上預定義命名查詢。
在需要呼叫的地方只要引用該查詢的名字即可。
例如:
@NamedQuery(name="getPerson", query= "FROM Person WHERE personid=?1")
@NamedQueries({ @NamedQuery(name="getPerson1", query= "FROM Person WHERE personid=?1"), @NamedQuery(name="getPersonList", query= "FROM Person WHERE age>?1") })
Query query = em.createNamedQuery("getPerson");
5.3 排序
JPQL也支援排序,類似於SQL中的語法。例如: Query query = em.createQuery("select p from Person p order by p.age, p.birthday desc");
5.4 聚合查詢
JPQL支援AVG、SUM、COUNT、MAX、MIN五個聚合函式。例如:
Query query = em.createQuery("select max(p.age) from Person p"); Object result = query.getSingleResult(); String maxAge = result.toString();
5.5 更新和刪除
JPQL不僅用於查詢,還可以用於批量更新和刪除。
如:
Query query = em.createQuery("update Order as o set o.amount=o.amount+10"); //update 的記錄數 int result = query.executeUpdate();
Query query = em.createQuery("delete from OrderItem item where item.order in(from Order as o where o.amount<100)"); query.executeUpdate();
query = em.createQuery("delete from Order as o where o.amount<100"); query.executeUpdate();//delete的記錄數
5.6 更多
與SQL類似,JPQL還涉及到更多的語法,可以參考:http://docs.oracle.com/cd/E11035_01/kodo41/full/html/ejb3_langref.html
6 事務管理
JPA支援本地事務管理(RESOURCELOCAL)和容器事務管理(JTA),容器事務管理只能用在EJB/Web容器環境中。
事務管理的型別可以在persistence.xml檔案中的“transaction-type”元素配置。
JPA中通過EntityManager的getTransaction()方法獲取事務的例項(EntityTransaction),之後可以呼叫事務的begin()、commit()、rollback()方法。
Date: 2012-12-30 16:46:29 CST
Org version 7.8.11 with Emacs version 24
Validate XHTML 1.0 轉:https://www.cnblogs.com/holbrook/archive/2012/12/30/2839842.html