日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

jpa 异常捕获_JPA和CMT –为什么捕获持久性异常不够?

發(fā)布時(shí)間:2023/12/3 编程问答 37 豆豆
生活随笔 收集整理的這篇文章主要介紹了 jpa 异常捕获_JPA和CMT –为什么捕获持久性异常不够? 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

jpa 異常捕獲

使用CMT( 容器管理的事務(wù) )進(jìn)入EJB和JPA的世界非常舒適。 只需定義一些注釋來劃分事務(wù)邊界(或使用默認(rèn)值)即可,僅此而已–無需擺弄手動(dòng)開始,提交或回滾操作。 回滾事務(wù)的一種方法是從EJB的業(yè)務(wù)方法中引發(fā)非應(yīng)用程序異常(或具有rollback = true的應(yīng)用程序異常)。 看起來很簡(jiǎn)單:如果在某些操作過程中可能會(huì)引發(fā)異常,并且您不想回滾tx,那么您應(yīng)該捕獲該異常就可以了。 現(xiàn)在,您可以在同一仍處于活動(dòng)狀態(tài)的事務(wù)中再次重試該易失性操作。

現(xiàn)在,對(duì)于從用戶組件拋出的應(yīng)用程序異常,這一切都是正確的 。 問題是– 除了其他組件引發(fā)的異常之外,還有什么? 就像JPA的EntityManager拋出PersistenceException ? 這就是故事的開始。

我們想要實(shí)現(xiàn)的目標(biāo)

設(shè)想以下情形:您有一個(gè)名為E的實(shí)體。它包含:

  • id –這是主鍵,
  • 名稱 -這是一些易于理解的實(shí)體名稱,
  • 內(nèi)容 –包含字符串的任意字段–它模擬“高級(jí)屬性”,例如,在持久性/合并期間進(jìn)行計(jì)算會(huì)導(dǎo)致錯(cuò)誤。
  • 代碼 –包含OK或ERROR字符串–定義高級(jí)屬性是否成功持久保存,

您要持久化E。您假定E的基本屬性將始終被成功持久化。 但是,高級(jí)屬性需要一些額外的計(jì)算或操作,這可能會(huì)導(dǎo)致例如從數(shù)據(jù)庫引發(fā)約束沖突。 如果發(fā)生這種情況,您仍然希望E保留在數(shù)據(jù)庫中(但僅填充基本屬性,并且將代碼屬性設(shè)置為“ ERROR”)。

換句話說,這是您可能想到的:

  • 堅(jiān)持E的基本屬性,
  • 嘗試使用脆弱的高級(jí)屬性對(duì)其進(jìn)行更新,
  • 如果從步驟2拋出了PersistenceException捕獲它,將'code'屬性設(shè)置為“ ERROR”并清除所有高級(jí)屬性(它們導(dǎo)致異常),
  • 更新E。
  • 天真的解決方案

    轉(zhuǎn)到EJB的代碼,這就是您可以嘗試執(zhí)行的方式(假設(shè)使用默認(rèn)的TransactionAttributes):

    public void mergeEntity() {MyEntity entity = new MyEntity('entityName', 'OK', 'DEFAULT');em.persist(entity);// This will raise DB constraint violationentity.setContent('tooLongContentValue');// We don't need em.merge(entity) - our entity is in managed mode.try {em.flush(); // Force the flushing to occur now, not during method commit.} catch (PersistenceException e) { // Clear the properties to be able to persist the entity.entity.setContent('');entity.setCode('ERROR');// We don't need em.merge(entity) - our entity is in managed mode.} }

    這個(gè)例子有什么問題?

    捕獲由EntityManager拋出的PersistenceException 不會(huì)阻止事務(wù)回滾 。 并不是在EJB中不緩存異常將tx標(biāo)記為回滾。 這是EntityManager 拋出的非應(yīng)用程序異常 ,將tx標(biāo)記為回滾。 更不用說資源本身可能會(huì)在內(nèi)部將tx標(biāo)記為回滾。 這實(shí)際上意味著您的應(yīng)用程序?qū)嶋H上無法控制此類tx行為。 此外,由于事務(wù)回滾,我們的實(shí)體已移至分離狀態(tài)。 因此,在此方法末尾需要一些em.merge(entity) 。

    工作方案

    那么如何處理這種自動(dòng)事務(wù)回滾? 因?yàn)槲覀冋谑褂肅MT,所以唯一的方法是定義另一種業(yè)務(wù)方法,該方法將啟動(dòng)新事務(wù)并在那里執(zhí)行所有易碎的操作 。 這樣,即使將拋出(并捕獲) PersistenceException ,它也將僅標(biāo)記要回滾的新事務(wù)。 我們的主要TX將保持不變。 在下面,您可以從此處看到一些代碼示例(為簡(jiǎn)潔起見,刪除了日志記錄語句):

    public void mergeEntity() {MyEntity entity = new MyEntity('entityName', 'OK', 'DEFAULT');em.persist(entity);try {self.tryMergingEntity(entity);} catch (UpdateException ex) {entity.setContent('');entity.setCode('ERROR');} }@TransactionAttribute(TransactionAttributeType.REQUIRES_NEW) public void tryMergingEntity(final MyEntity entity) throws UpdateException {entity.setContent('tooLongContentValue');em.merge(entity);try {em.flush();} catch (PersistenceException e) {throw new UpdateException();} }

    注意:

    • UpdateException是@ApplicationException ,它擴(kuò)展了Exception(因此默認(rèn)情況下為rollback=false )。 用于通知更新操作失敗。 或者,您可以更改tryMergingEntity(-)方法簽名以返回布爾值而不是void。 此布爾值可以描述更新是否成功。
    • self是對(duì)我們自己的EJB的自我引用。 這是使用EJB容器代理的必需步驟,該代理使被調(diào)用方法的@TransactionAttribute起作用。 或者,您可以使用SessionContext#getBusinessObject(clazz).tryMergingEntity(entity) 。
    • em.merge(entity)是至關(guān)重要的。 我們正在tryMergingEntity(-)中開始新事務(wù),因此該實(shí)體不在持久性上下文中。
    • 此方法不需要任何其他合并或刷新。 tx尚未回滾,因此批準(zhǔn)了CMT的常規(guī)功能,這意味著在tx提交期間將自動(dòng)刷新對(duì)實(shí)體的所有更改。

    讓我們?cè)俅螐?qiáng)調(diào)最重要的一點(diǎn): 如果您捕獲到異常,并不表示您當(dāng)前的事務(wù)沒有被標(biāo)記為回滾。 PersistenceException不是ApplicationException,即使您是否捕獲它,也將使您的tx回滾。

    JTA BMT解決方案

    我們一直在談?wù)揅MT。 JTA BMT呢? 好吧,作為一個(gè)好處,找到下面的代碼,該代碼顯示如何使用BMT處理此問題(也可在此處訪問):

    public void mergeEntity() throws Exception {utx.begin();MyEntity entity = new MyEntity('entityName', 'OK', 'DEFAULT');em.persist(entity);utx.commit();utx.begin();entity.setContent('tooLongContentValue');em.merge(entity);try {em.flush();} catch (PersistenceException e) {utx.rollback();utx.begin();entity.setContent('');entity.setCode('ERROR');em.merge(entity);utx.commit();} }

    使用JTA BMT,我們可以用一種方法來完成所有這一切。 這是因?yàn)槲覀兛刂浦鴗x何時(shí)開始以及提交/回滾 (看看那些utx.begin()/ commit()/ rollback()。盡管如此,結(jié)果還是一樣的–拋出PersistenceException我們的tx被標(biāo)記為回滾然后您可以使用UserTransaction#getStatus()進(jìn)行檢查,并將其與諸如Status.STATUS_MARKED_ROLLBACK之類的常量進(jìn)行比較,并可以在我的GitHub帳戶上檢查整個(gè)代碼。

    參考: JPA和CMT –為什么捕獲持久性異常不足? 從我們的JCG合作伙伴 Piotr Nowicki在Piotr Nowicki的首頁博客中獲得。

    翻譯自: https://www.javacodegeeks.com/2013/03/jpa-and-cmt-why-catching-persistence-exception-is-not-enough.html

    jpa 異常捕獲

    總結(jié)

    以上是生活随笔為你收集整理的jpa 异常捕获_JPA和CMT –为什么捕获持久性异常不够?的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。