1.JPA的實體生命週期:
JPA的實體有以下4中生命週期狀態:
(1).New:瞬時對象,尚未有id,還未和Persistence Context建立關聯的對象。
(2).Managed:持久化受管對象,有id值,已經和Persistence Context建立了關聯的對象。
(3).Datached:遊離態離線對象,有id值,但沒有和Persistence Context建立關聯的對象。
(4).Removed:刪除的對象,有id值,尚且和Persistence Context有關聯,但是已經準備好從數據庫中刪除。
四種狀態總結:
狀態名 作爲java對象存在 在實體管理器中存在 在數據庫存在
New yes no no
Managed yes yes yes
Detached no no no
Removed yes yes no
2.JPA實體狀態的切換:
JPA實體的四種狀態之間可以進行切換,具體如下:
3.容器管理和應用程序管理的EntityManager實體管理器:
在JPA中有兩種管理實體管理器的方法:
(1).容器管理(Container-Manager)的實體管理器:
容器管理實體管理器,是由JavaEE容器所管理的實體管理器,通過PersistenceContext注入方式來生成實體管理器,具體代碼如下:
@PersistenceContext(unitName=”持久化單元名稱”)
Protected EntityManager em;
(2).應用程序管理(Application-Manager)的實體管理器:
JPA不但可以在JavaEE容器中使用,也可以脫離JavaEE容器在JavaSE程序中使用,當JPA脫離了JavaEE服務器環境時,就需要通過應用程序來獲取實體管理器,具體代碼如下:
a. 代碼方式:
//首先根據持久化單元創建實體管理器工廠
EntityManagerFactory emf = Persistence.createEntityManagerFacotory(持久化策略文件中的持久化單元名稱);
//通過實體管理器工廠創建實體管理器
EntityManager em = emf.createEntityManager();
b. 註解方式:
//將持久化單元注入實體管理器工廠中
@PersistenceUnit(持久化單元名稱)
protected EntityManager emf;
protected EntityManager em = emf.createEntityManager();
注意:當持久化策略文件中只有一個持久化單元時,在註解中不用指定支持化單元名稱。
4.JPA實體管理器的常用方法:
(1).find查找:相當於Hibernate中的get操作,如果一級緩存查找不到會立即去數據庫查找,如果查找不到會返回null。
(2).getReference查找:相當於Hibernate中的load操作,如果一級緩存查找不到並不立即去數據庫查找,而是去查找二級緩存,返回實體對象的代理,如果查找不到會拋出ObjectNotFindException。
(3).persist:使實體類從new狀態或者removed轉變到managed狀態,並將數據保存到底層數據庫中。
(4).remove:將實體變爲removed狀態,當實體管理器關閉或者刷新時,纔會真正地刪除數據。
(5).flush:將實體和底層數據庫進行同步,當調用persist、merge或者remove方法時,更新並不會立刻同步到數據庫中,直到容器決定刷新到數據庫中時纔會執行,可以調用flush強制刷新。
(6).createQuery:根據JPA QL定義查詢對象。
(7).createNativeQuery:允許開發人員根據特定數據庫的SQL語法來進行查詢操作,只有JPA QL不能滿足要求時才使用,不推薦使用,因爲增加了程序可移植性。
(8).createNamedQuery:根據實體中標註的命名查詢創建查詢對象。
(9).merge:將一個detached的實體持久化到數據庫中,並轉換爲managed狀態。
5.JPA分頁查詢:
(1).爲實體管理器創建的查詢對象設置返回最大結果數:setMaxResults(int maxResult);
(2).爲實體管理器創建的查詢對象設置返回結果開始下標:setFirstResult(int firstResult);
6.JPA中調用存儲過程:
注意:JPA中只能調用兩種存儲過程:1.無返回值的存儲過程。2.返回值爲ResultSet的存儲過程(不能是out)。
實體管理器的createNativeQuery(”{call 存儲過程名()}”);即可調用數據庫的存儲過程。
7.JPA的命名參數:
語法:“:參數名”。
例如:
Query query = entityManager.createQuery(”select u from User u where u.name=:name”);
//設置查詢中的命名參數
Query.setParameter(“name”, testName);
注意:不允許在同一個查詢中使用兩個相同名字的命名參數。
8.JPA的位置參數:
語法:“?位置參數索引”。
例如:
Query query = entityManager.createQuery(”select u from User u where u.name=?1”);
//設置查詢中的位置參數
Query.setParameter(1, testName);
注意:JPA中的位置參數索引值從1開始。
9.JPA的集合查詢:
我們知道在SQL語句中,查找某元素是否在某個集合中時常用類似:in(a,b,c)的查詢語句,在JDBC中我們常常需要將集合元素拼接成以逗號(“,”)分隔的字符串,在JPA中有兩種方法可以方便地進行判斷元素是否在集合中的查詢:
(1).設置集合類型的參數:
查詢對象的setParameter方法支持Object類型,因此可以傳入一個集合類型的參數,如數組或者ArrayList等。
例如:
Query query = em.createQuery(“select * from Users where name in(?names)”);
query.setParameter(“name”, names);//names是一個name集合
(2).使用member of關鍵字:
例如:
Select t from Topic t where :option member of t.options;
10.JPA的回調方法:
JPA中,實體類支持一些回調方法,可以通過如下的註解指定回調方法:
(1).@PrePersist:在persist方法調用後立刻發生,級聯保存也會發生該事件,此時數據還沒有真實插入數據庫中。
(2).@PostPersist:數據已經插入進數據庫中後觸發。
(3).@PreRemove:在實體從數據庫刪除之前觸發。級聯刪除也會觸發該事件,此時數據還沒有真實從數據庫中刪除。
(4).@PostRemove:在實體已經從數據庫中刪除後觸發。
(5).@PreUpdate:在實體的狀態同步到數據庫之前觸發,此時數據還沒有真實更新到數據庫中。
(6).@PostUpdate:在實體的狀態同步到數據庫後觸發,同步在事務提交時發生。
(7).@PostLoad:在以下情況觸發:
a.執行find或者getReference方法載入一個實體之後。
b.執行JPA QL查詢之後。
c.refresh方法被調用之後。
11.事務管理特性:
事務所數據庫的一個邏輯工作單元,包含一系列的操作,事務有四個特性,即ACID特性:
(1).Atomic(原子性):
事務中的各個操作不可分割,事務中所包含的操作被看作一個邏輯單元,這個邏輯單元中的操作要麼全部成功,要麼全部失敗。
(2).Consistency(一致性):
一致性意味着,只有合法的數據纔可以被寫入數據庫,如果數據有任何不符合,則事務應該將其回滾。
(3).Isolation(隔離性):
事務允許多個用戶對同一個數據的併發訪問,而不破壞數據的正確性和完整性。同時,並行事務的修改必須與其他並行事務的修改相互獨立。按照比較嚴格隔離邏輯來講,一個事務看到的數據要麼是另外一個事務修改這些數據之前的狀態,要麼是一個事務已經修改完成的數據,決不能是其他事務正在修改的數據。
(4).Durability(持久性):
事務結束後,事務處理的結果必須能夠得到持久化。
12.數據操作過程中可能會出現的3中不確定情況:
(1).髒讀取:
一個事務讀取了另一個並行事務未提交的數據。
(2).不可重複讀:
一個事務再次讀取之前曾經讀過的數據時,發現該數據已經被另一個已提交的事務修改。
(3).幻讀:
同一查詢在同一事務中多次進行,由於其他事務提交所做的操作,使得每次返回不同的結果集,從而產生換讀。
13.事務的隔離級別:
事務的隔離,是指數據庫(或其他事務系統)通過某種機制,在並行的多個事務之間進行分割,使得每個事務在其執行過程中保持獨立,如同當前只有一個事務在單獨運行。爲了避免12中3中不確定情況的發生,標準的SQL規範中定義瞭如下4中事務隔離級別:
(1).爲提交讀:
最低等級的事務隔離,僅僅保證了讀取過程中不會讀取到非法數據。
(2).已提交讀:
該級別的事務隔離保證了一個事務不會讀取到另一個並行事務已修改但未提交的數據,避免了髒讀。大多數主流數據庫默認的事務隔離等級是已提交讀。
(3).重複讀:
該級別的事務隔離避免了髒讀和不可重複讀,但是也意味着,一個事務部可能更新已經由另一個事務讀取但未提交的數據。
(4).序列化:
最高等級的事務隔離,也提供了最嚴格的隔離機制,上面3種不確定情況都可以被避免。該級別將模擬事務的串行執行,邏輯上如同所有的事務都處於一個執行隊列中,依次串行執行,而非並行執行。
4種事務隔離級別總結:
隔離等級 髒讀 不可重複讀 幻讀
未提交讀 可能 可能 可能
提交讀 不可能 可能 可能
重複讀 不可能 不可能 可能
序列化 不可能 不可能 不可能
9. JDBC事務和JTA事務:
JDBC事務:只能支持一個數據庫,單數據源,一個由數據庫本身來執行提交或回滾,單階段提交,本地事務。JDBC事務由Connection管理,事務週期侷限於Connection的生命週期之內。
JTA事務:JTA提供了跨Session的事務管理能力,支持多數據源的分佈式事務,兩階段提交。JTA事務管理由JTA容器實現,JTA容器對當前加入事務的衆多Connection進行調度,實現其事務性要求,JTA的事務週期可橫跨多個JDBC Connection生命週期。
10. 事務的傳播特性:
事務傳播特性是用於指定當進行操作時,如何使用事務,JPA中有以下6種事務傳播特性:
(1).Not Support:不支持,若當前事務有上下文,則掛起。
(2).Support:支持,若有事務,則使用事務,若無事務,則不使用事務。
(3).Required:需要,若有事務,則使用使用,若無事務,則創建新的事務。
(4).Required New:需要新事務,每次都會創建新的事務。
(5).Mandatory:必須有事務,若無事務,則將拋出異常。
(6).Never:必須不能有事務,若有事務,則會拋出異常。
16.鎖的機制:
所謂鎖,就是給選定的目標對象加上限制,使其無法被其他程序所修改,JPA支持兩種鎖機制:樂觀鎖和悲觀鎖。
(1).悲觀鎖:
對數據被外界修改持保守態度,在整個數據處理過程中,將數據處於鎖定狀態,悲觀鎖的實現,往往依靠數據庫提供的鎖機制。最常用的悲觀鎖是在查詢時加上“for update“,用法如下:
Select * from user where name=”test” for update
在JPA中,可以通過給Query對象設置鎖模式(query.setLockMode)來制定悲觀鎖的模式:
a.LockMode.NONE:無鎖機制。
b.LockMode.WRITE:在insert和update時會自動加鎖。
c.LockMode.READ:在讀取記錄時會自動加鎖。
d.LockMode.UPGRADE:利用數據庫的for update字句加鎖。
(2).樂觀鎖:
相對於悲觀鎖,樂觀鎖機制採用較爲寬鬆的加鎖機制,悲觀鎖大多數情況下依靠數據庫鎖的機制實現,以保證操作最大程度的獨佔性,但是數據庫的性能開銷比較大。而樂觀鎖大多數基於數據版本(version)記錄或者時間戳機制實現。
基於版本的樂觀鎖在讀取數據時將數據的版本號一同讀出,之後更新則對版本號加1,提交時對數據的版本與數據庫中對應的版本進行比較,如果提交數據數據版本號打於數據庫中當前版本號,則予以更新,否則認爲是過期數據。樂觀鎖大大減小了數據庫開銷,提高了程序的性能。
JPA中可以在實體中使用@Version註解指定其使用樂觀鎖,JPA會在數據庫對應的表中自動生成和維護一列版本號。
17.Spring集成JPA:
JPA不但可以在JavaEE環境中使用,也可以還JavaSE環境中使用,spring現在在java開發中應用非常廣泛,Spring同樣提供了對JPA的強大支持。Spring集成JPA的步驟如下:
(1).在MATE-INF下添加JPA的持久化策略文件,開發實體bean。
(2).爲工程引入Spring支持。添加Spring相關依賴包和spring配置文件。
(3).在spring配置文件中加入JPA配置如下:
<bean id=”entityManagerFactory”
class=”org.springframework.orm.jpa.LocalEntityManagerFactoryBean”>
<property name=”persistenceUnitName” value=”持久化單元名稱”/>
</bean>
<bean id=”transactionManager”
class=”org.springframework.orm.jpa.JpaTransactionManager”>
<property name=”entityManagerFactory” ref=” entityManagerFactory”/>
</bean>
<tx:annotation-driven transaction-manager=” transactionManager”/>
至此,Spring和JPA的簡單集成完成。