entitymanager_实体管理器的类型:应用程序管理的EntityManager
entitymanager
JPA規(guī)范定義了幾種類型的EntityManagers / Persistence Context。 我們可以有:
- 擴(kuò)展和事務(wù)范圍的EntityManager,
- 容器管理或應(yīng)用程序管理的EntityManager。
- JTA或本地資源EntityManager,
除了上述區(qū)別之外,我們還可以在其中存在EntityManager / Persistence Context的兩個(gè)主要上下文– Java EE和Java SE 。 并非每個(gè)選項(xiàng)都適用于Java EE,并且并非每個(gè)選項(xiàng)都適用于Java SE。 在本文的其余部分中, 我將介紹Java EE環(huán)境 。
好的,因此在繼續(xù)本文之前的主題之前(這是使用EntityManagerFactory手動(dòng)創(chuàng)建的Java EE中EntityManager的行為),我們僅簡要介紹一下上述EM類型。
擴(kuò)展與事務(wù)范圍
此功能告訴我們EntityManager的操作是否可能跨越多個(gè)事務(wù)。 默認(rèn)情況下,使用事務(wù)性持久性上下文,這意味著當(dāng)提交當(dāng)前事務(wù)時(shí),將清除所有更改,并分離所有受管實(shí)體。 擴(kuò)展范圍僅適用于有狀態(tài)EJB。 這非常有意義,因?yàn)镾FSB可以保存狀態(tài),因此不必終止一種業(yè)務(wù)方法就意味著結(jié)束事務(wù)。 使用SLSB的情況就不同了–我們有業(yè)務(wù)方法必須在業(yè)務(wù)方法完成時(shí)結(jié)束,因?yàn)樵谙乱淮握{(diào)用中,我們不知道我們將以哪個(gè)EJB實(shí)例結(jié)束。 SLSB僅允許使用事務(wù)范圍的EntityManager。 您可以控制在EntityManager注入期間EntityManager是擴(kuò)展的還是事務(wù)的:
@PersistenceContext(type=javax.persistence.PersistenceContextType.EXTENDED) EntityManager em;默認(rèn)情況下為javax.persistence.PersistenceContextType.TRANSACTION 。 附帶說明–使用擴(kuò)展的EntityManager可能使您可以創(chuàng)建一些有趣的解決方案; 看看具有事務(wù)性保存方法技巧的 Adam Bien的無事務(wù)bean 。 他使用這種方法使事務(wù)開始和結(jié)束時(shí)自動(dòng)清除所有更改(并且他實(shí)際上通過調(diào)用特殊的人工方法來做到這一點(diǎn)。)僅在容器管理的EntityManagers的情況下才允許擴(kuò)展和事務(wù)范圍的PersistenceContext。
容器管理與應(yīng)用程序管理
在大多數(shù)Java EE應(yīng)用程序中,您只是使用@PersistenceContext注入EntityManager,如下所示:
@PersistenceContext EntityManager em;實(shí)際上,這意味著您要讓容器為您的EntityManager注入 (容器是在后臺(tái)從EntityManagerFactory創(chuàng)建的。)這意味著EntityManager是由容器管理的。 另外,您可以從EntityManagerFactory自己創(chuàng)建EntityManager。 您可以通過注入獲得它:
@PersistenceUnit EntityManagerFactory emf;然后,要獲取EntityManager,您需要調(diào)用emf.createEntityManager() 。 這就是–您現(xiàn)在正在使用應(yīng)用程序管理的EntityManager 。 應(yīng)用程序(您)負(fù)責(zé)創(chuàng)建和刪除EntityManager。 每個(gè)應(yīng)用程序管理的持久性上下文都有擴(kuò)展的范圍。
如果要控制已創(chuàng)建的EM,則可以使用-例如,如果要為基礎(chǔ)JPA實(shí)現(xiàn)程序設(shè)置一些屬性,或者只是在業(yè)務(wù)方法將其投入使用之前插入自己。 但是,您將需要跨事務(wù)涉及的多個(gè)bean移動(dòng)創(chuàng)建的EntityManager –容器不會(huì)為您這樣做,并且每次調(diào)用emf.createEntityManager()您都在創(chuàng)建一個(gè)與新PersistenceContext連接的EntityManager。 。 您可以使用CDI進(jìn)行EntityManager的共享,但這是最后一節(jié)之一的主題。
JTA與本地資源
此屬性定義您是要JTA管理EntityManager的事務(wù),還是要使用其直接API開始和提交。 如果您使用的是容器管理的EntityManager,則自動(dòng)意味著您必須使用JTA EntityManager 。 如果您使用的是應(yīng)用程序管理的EntityManager,則可以使用JTA或本地資源。 在現(xiàn)實(shí)生活中,這意味著,如果您使用的是JTA EntityManager,則您只需照顧更高級(jí)別的事務(wù)管理:
- 聲明性地 使用注釋或XML JTA交易屬性,或
- 以編程方式 使用javax.transaction.UserTransaction 。
如果您使用的是本地資源EntityManager,則需要更深入一點(diǎn),并使用EntityManager.getTransaction()返回javax.persistence.EntityTransaction并調(diào)用commit(-) , begin(-) , rollback()等。使用transaction-type屬性在persistence.xml定義此功能:
<?xml version='1.0' encoding='UTF-8'?> <persistence ...><persistence-unit transaction-type='RESOURCE_LOCAL' ... > </persistence>另一個(gè)可能的值(當(dāng)未定義transaction-type時(shí)為默認(rèn)值)是JTA 。
Java EE中由應(yīng)用程序管理的JTA EntityManager
盡管此字幕聽起來很復(fù)雜,但了解EntityManager和PersistenceContexts的所有先前類型后,您應(yīng)該確切了解if指的是什么。
- “應(yīng)用程序托管”意味著我們將注入@PersistenceUnit EntityManagerFactory而不是EntityManager,
- 之所以稱為 “ Java EE”,是因?yàn)檫@些示例(在github上發(fā)布)僅在Java EE Application Server中使用 ,
- “ JTA”,因?yàn)槲覀儗⑹褂肑TA事務(wù)級(jí)別,因此不會(huì)使用javax.persistence.EntityTransaction 。
現(xiàn)在,您需要了解的第一件事是如何使用JTA事務(wù)。 JTA事務(wù)管理有兩種類型-容器(CMT)和Bean管理(BMT)。 容器管理的JTA事務(wù) ( CMT )意味著您使用javax.ejb.TransactionAttribute定義tx是否應(yīng)處于活動(dòng)狀態(tài)以及事務(wù)邊界在何處。 這是默認(rèn)的JTA管理類型。 或者,您可以選擇自己劃定JTA事務(wù)的邊界。 這稱為Bean管理的JTA事務(wù) ( BMT )。應(yīng)用程序(您)負(fù)責(zé)啟動(dòng),回滾或提交事務(wù)。 您如何控制JTA交易? 您可以使用javax.transaction.UserTransaction做到這一點(diǎn)。
您如何獲得一個(gè)? 好吧,至少有3種方法可以做到這一點(diǎn):
- 它綁定到組件私有名稱空間( java:comp/UserTransaction )中的JNDI,因此您可以使用InitialContext或SessionContext對(duì)其進(jìn)行查找,
- 您可以使用SessionContext進(jìn)行訪問– SessionContext#getUserTransaction() ,
- 因?yàn)樗壎ㄔ诒娝苤腏NDI名稱中,所以可以讓容器使用以下方式注入它: @Resource UserTransaction utx; 。
如果您有UserTransaction ,則可以開始劃分事務(wù)中要執(zhí)行的內(nèi)容。 請(qǐng)注意,您仍在控制JTA事務(wù) –您甚至都沒有接觸EntityManager的資源本地事務(wù)。
EntityManager何時(shí)在JTA事務(wù)中?
如果沒有前面的介紹,您可能會(huì)認(rèn)為由應(yīng)用程序管理的EntityManager意味著您將獨(dú)自承擔(dān)一切–創(chuàng)建,共享EntityManager,開始tx,提交,關(guān)閉。 但是,了解了以上所有差異后,您知道可以在應(yīng)用程序管理的EntityManager中使用JTA事務(wù) 。 但是問題是–如何使它知道活動(dòng)的JTA事務(wù)? 如果我們有一個(gè)容器管理的EntityManager,我們知道容器將全部管理它,但是如果我們是一個(gè)人,我們該怎么做? 實(shí)際上, 這取決于我們在哪里創(chuàng)建EntityManager 。 在下面找到一些示例(完整的代碼可以在我的github帳戶上找到:
情況1:我們在沒有活動(dòng)交易的情況下調(diào)用以下代碼(因此,對(duì)于CMT,我們具有TransactionAttribute.NEVER或TransactionAttribute.NOT_SUPPORTED ;對(duì)于BMT,我們不調(diào)用UserTransaction.begin() :
EntityManager em = emf.createEntityManager(); em.persist(new Customer(firstName, lastName));結(jié)果: EntityManager操作在持久化時(shí)不會(huì)引發(fā)任何異常,但是所有更改都不會(huì)提交 。 沒有活動(dòng)的事務(wù),因此不會(huì)進(jìn)行任何更改。
情況2:我們使用BMT調(diào)用以下代碼:
utx.begin();EntityManager em = emf.createEntityManager();em.persist(new Customer(firstName, lastName));utx.commit();結(jié)果:在JTA提交期間,新數(shù)據(jù)已正確保留(在最后一行。)
情況3:我們使用BMT調(diào)用以下代碼:
EntityManager em = emf.createEntityManager(); utx.begin();em.persist(new Customer(firstName, lastName));utx.commit();結(jié)果: EntityManager在事務(wù)之外,因?yàn)樗窃趩?dòng)JTA事務(wù)之前創(chuàng)建的。 盡管已提交JTA事務(wù),但更改不會(huì)持久保存。 沒有異常被拋出。
在第二個(gè)示例的情況下,您可能會(huì)問自己-是否可以首先創(chuàng)建EntityManager,然后開始事務(wù),最后以某種方式使EntityManager知道周圍的TX? 如果事實(shí)是這樣,則可以執(zhí)行此操作,而這正是EntityManager#joinTransaction()方法的用途。 以下兩種情況將向您展示如何使用它:
情況4:我們使用BMT調(diào)用以下代碼:
EntityManager em = emf.createEntityManager(); utx.begin(); em.joinTransaction();em.persist(new Customer(firstName, lastName));utx.commit();結(jié)果:在這里,我們明確地告訴EntityManager加入活動(dòng)的JTA事務(wù)。 結(jié)果, EntityManager將在JTA commit期間刷新其所有更改 。
情況5:我們使用BMT調(diào)用以下代碼:
EntityManager em = emf.createEntityManager(); utx.begin();em.joinTransaction();em.persist(new Customer(firstName, lastName));utx.commit();utx.begin();em.joinTransaction();em.persist(new Customer(firstName, lastName));utx.commit();結(jié)果: 兩種EntityManager操作均正確存在。 在這里,我們證明了應(yīng)用程序管理的持久性上下文可以跨越多個(gè)JTA事務(wù) (請(qǐng)注意,我們沒有創(chuàng)建另一個(gè)EntityManager,而只是重用了先前事務(wù)中使用的那個(gè))。在這里,您可以看到JPA規(guī)范(JPA規(guī)范) 2.0最終版本)告訴您有關(guān)應(yīng)用程序管理的持久性上下文的信息:
7.7應(yīng)用程序管理的持久性上下文
使用JTA應(yīng)用程序管理的實(shí)體管理器時(shí),如果在當(dāng)前JTA事務(wù)的范圍之外創(chuàng)建實(shí)體管理器,則應(yīng)用程序有責(zé)任通過調(diào)用EntityManager.joinTransaction將實(shí)體管理器與事務(wù)關(guān)聯(lián)(如果需要)。 。 如果實(shí)體管理器是在JTA事務(wù)范圍之外創(chuàng)建的,則除非調(diào)用EntityManager.joinTransaction,否則它不與事務(wù)關(guān)聯(lián)。
使用CDI共享EntityManager
如前所述,如果要在組成一個(gè)事務(wù)的組件之間共享EntityManager,則應(yīng)手動(dòng)傳遞它(畢竟,它是“應(yīng)用程序管理的”。)CDI可能是此處的解決方案。 您可以生成請(qǐng)求范圍內(nèi)的EntityManager并將其注入所需的任何組件中。 看起來可能像這樣(在現(xiàn)實(shí)生活中,您還需要注意處理EM):
public class Resources {@PersistenceUnitEntityManagerFactory emf;@Produces @RequestScopedpublic EntityManager createEntityManager() {return emf.createEntityManager();} }現(xiàn)在,在每個(gè)bean中我們都可以擁有:
@Stateless public class MyBean {@InjectEntityManager em; }在構(gòu)成事務(wù)的不同組件之間共享應(yīng)用程序管理的持久性上下文似乎是一種非常干凈的方法。 但是,我擔(dān)心的是:知道由應(yīng)用程序管理的EntityManager事務(wù)性行為取決于創(chuàng)建它的位置 ,因此這種方法有時(shí)可能會(huì)給您帶來討厭的結(jié)果。 以下面的代碼為例( 我的Github項(xiàng)目中也提供了該類,該類正是在這里 ):
@Stateless @TransactionAttribute(TransactionAttributeType.NEVER) public class BeanABoundary {@Injectprivate EntityManager em;@EJBBeanB beanB;public void invoke() {em.getProperties();beanB.invoke(); }請(qǐng)注意,BeanA是非事務(wù)性資源。 還要注意,我們在EntityManager上注入并調(diào)用了一些操作 (這使得注入實(shí)際上得以執(zhí)行。)現(xiàn)在,如果BeanB是事務(wù)性的,并且還注入并使用EntityManager –我們將以非事務(wù)性EntityManager結(jié)束,該操作不會(huì)拋出任何異常,并且不會(huì)將任何更改保存到數(shù)據(jù)庫 。
在舊的@PersistenceContext的情況下,我們將處于事務(wù)中,因?yàn)镋ntityManager將由容器管理,并且容器將知道當(dāng)前處于活動(dòng)狀態(tài)的事務(wù)。 容器負(fù)責(zé)在事務(wù)邊界之間共享EntityManager。 在顯示CDI生產(chǎn)者方法的情況下,CDI不知道運(yùn)行事務(wù),而只是共享EntityManager。
當(dāng)然,可以使用CDI并創(chuàng)建一個(gè)@Produces @PersistenceContext EntityManager em ,然后使用@Inject EntityManager 。 這將與@PersistenceContext EntityManager完全一樣,但是允許我們在產(chǎn)生EntityManager的單個(gè)位置定義(例如)持久性單元的名稱。 但是,如果我們要擁有一個(gè)應(yīng)用程序管理的EntityManager,則這不是一個(gè)選擇。
參考: 實(shí)體管理器的類型:由我們的JCG合作伙伴 Piotr Nowicki在Piotr Nowicki主頁博客上進(jìn)行的應(yīng)用程序管理的EntityManager 。
翻譯自: https://www.javacodegeeks.com/2013/03/types-of-entity-managers-application-managed-entitymanager.html
entitymanager
總結(jié)
以上是生活随笔為你收集整理的entitymanager_实体管理器的类型:应用程序管理的EntityManager的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 使用Payara Micro的Easy
- 下一篇: CDI中的事务异常处理