使用CMT( 容器管理的事务 )进入EJB和JPA的世界非常舒适。 只需定义一些注释来划分事务边界即可(或使用默认值),仅此而已–无需摆弄手动开始,提交或回滚操作。 回滚事务的一种方法是从EJB的业务方法中引发非应用程序异常(或具有rollback = true的应用程序异常)。 看起来很简单:如果在某些操作过程中可能会引发异常,并且您不想回滚tx,那么您应该捕获该异常就可以了。 现在,您可以在同一仍处于活动状态的事务中再次重试该易失性操作。

现在,对于从用户组件抛出的应用程序异常,这一切都是正确 。 问题是– 除了其他组件引发的异常之外,还有什么? 就像JPA的EntityManager抛出PersistenceException ? 这就是故事的开始。

我们想要实现的目标

设想以下情形:您有一个名为E的实体。它包含:

  • id –这是主键,
  • 名称 -这是一些易于理解的实体名称,
  • 内容 -包含字符串的任意字段-它模拟“高级属性”,例如,在持久性/合并期间进行计算会导致错误。
  • 代码 –包含OK或ERROR字符串–定义高级属性是否成功持久保存,

您要持久化E。您假定E的基本属性将始终被成功持久化。 但是,高级属性需要一些额外的计算或操作,这可能会导致例如从数据库引发约束冲突。 如果发生这种情况,您仍然希望E保留在数据库中(但仅填充基本属性,并且将代码属性设置为“ ERROR”)。

换句话说,这就是您可能想到的:

  1. 坚持E的基本属性,
  2. 尝试使用脆弱的高级属性进行更新,
  3. 如果从步骤2抛出了PersistenceException捕获它,将'code'属性设置为“ ERROR”并清除所有高级属性(它们导致异常),
  4. 更新E。

天真的解决方案

转到EJB的代码,这就是您可以尝试执行的方式(假设使用默认的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.}
}

这个例子有什么问题?

捕获由EntityManager抛出的PersistenceException 不会阻止事务回滚 。 并不是在EJB中不缓存异常会使tx标记为回滚。 这是EntityManager 抛出的非应用程序异常 ,将tx标记为回滚。 更不用说资源可能会在其内部将tx标记为回滚。 这实际上意味着您的应用程序实际上无法控制此类tx行为。 此外,由于事务回滚,我们的实体已移至分离状态。 因此,此方法末尾需要一些em.merge(entity)

工作方案

那么如何处理这种自动事务回滚? 因为我们使用的是CMT,所以唯一的方法是定义另一种业务方法,该方法将启动新的事务并在那里执行所有易碎的操作 。 这样,即使将抛出(并捕获) PersistenceException ,它也将仅标记要回滚的新事务。 我们的主要TX将保持不变。 在下面,您可以从此处看到一些代码示例(为简洁起见,删除了日志记录语句):

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 ,它扩展了Exception(因此默认情况下为rollback=false )。 用于通知更新操作失败。 或者,您可以更改tryMergingEntity(-)方法签名以返回布尔值而不是void。 该布尔值可以描述更新是否成功。
  • self是对我们自己的EJB的自我引用。 这是使用EJB容器代理的必需步骤,该代理使被调用方法的@TransactionAttribute起作用。 或者,您可以使用SessionContext#getBusinessObject(clazz).tryMergingEntity(entity)
  • em.merge(entity)是至关重要的。 我们正在tryMergingEntity(-)中开始新事务,因此该实体不在持久性上下文中。
  • 此方法不需要任何其他合并或刷新。 tx尚未回滚,因此批准了CMT的常规功能,这意味着在tx提交期间将自动刷新对实体的所有更改。

让我们再次强调最重要的一点: 如果您捕获到异常,这并不意味着您的当前事务没有被标记为回滚。 PersistenceException不是ApplicationException,即使您是否捕获它,也将使您的tx回滚。

JTA BMT解决方案

我们一直在谈论CMT。 JTA BMT呢? 好吧,作为奖励,请找到以下代码,该代码显示了如何使用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,我们可以用一种方法完成所有这一切。 这是因为我们控制着tx何时开始以及提交/回滚 (看看那些utx.begin()/ commit()/ rollback()。尽管如此,结果还是一样的–抛出PersistenceException我们的tx被标记为回滚然后可以使用UserTransaction#getStatus()进行检查,并将其与诸如Status.STATUS_MARKED_ROLLBACK之类的常量进行比较,并可以在我的GitHub帐户上检查整个代码。

参考: 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和CMT –为什么捕获持久性异常不够?相关推荐

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

    jpa 异常捕获 使用CMT( 容器管理的事务 )进入EJB和JPA的世界非常舒适. 只需定义一些注释来划分事务边界(或使用默认值)即可,仅此而已–无需摆弄手动开始,提交或回滚操作. 回滚事务的一种方 ...

  2. WCF客户端不能用在Using语句块中,因为它可能会抛出不可预知的异常。即使你捕获了异常,仍有可能一直保持连接。...

    WCF客户端不能用在Using语句块中,因为它可能会抛出不可预知的异常.即使你捕获了异常,仍有可能一直保持连接.让我们来看看形成这一问题的历史原因,并提出几个补救措施. 在.NET中,资源管理的基础就 ...

  3. winform程序捕获全局异常,对错误信息写入日志并弹窗

    使用场景:在winform程序中如果没对方法进行try catch操作,若方法内出错,则整个程序报错并退出,如下图 如果程序已在客户手中,若没对错误的详细信息进行拍照,我们则不知道错误原因是什么.我们 ...

  4. java try catch嵌套_解析Java中未被捕获的异常以及try语句的嵌套使用

    Java未被捕获的异常 在你学习在程序中处理异常之前,看一看如果你不处理它们会有什么情况发生是很有好处的.下面的小程序包括一个故意导致被零除错误的表达式. class Exc0 { public st ...

  5. python——异常(1),捕获特定异常

    python--异常(1),捕获特定异常 参考文章: (1)python--异常(1),捕获特定异常 (2)https://www.cnblogs.com/kekefu/p/12317986.html ...

  6. PHP 捕获全局异常

    PHP 捕获全局异常 参考文章: (1)PHP 捕获全局异常 (2)https://www.cnblogs.com/yaomao/p/11260388.html (3)https://www.java ...

  7. Java并发-UncaughtExceptionHandler捕获线程异常信息并重新启动线程

    Java并发-UncaughtExceptionHandler捕获线程异常信息并重新启动线程 参考文章: (1)Java并发-UncaughtExceptionHandler捕获线程异常信息并重新启动 ...

  8. C# winform 捕获全局异常

    using System; using System.Collections.Generic; using System.Windows.Forms; using System.IO; namespa ...

  9. Android application捕获崩溃异常

    Java代码 个人笔记: 通用 application 1.收集所有 avtivity 用于彻底退出应用 2.捕获崩溃异常,保存错误日志,并重启应用 public class HKBaseApplic ...

最新文章

  1. iOS开发笔记 - 界面调试神器Reveal
  2. Hibernate查询缓存如何工作
  3. python运行input不出结果_Python中print和input调用了Python中底层的什么方法
  4. 《全唐诗》前言和后记
  5. python的config模块_python中ConfigParse模块的用法
  6. pytorch 实现张量tensor,图片,CPU,GPU,数组等的转换
  7. 解决办法一:GetProcAddress函数返回值总为NULL
  8. 使用lockf()保证应用单进程
  9. 显卡功耗测试用什么软件,显卡功耗测试_AMD显卡_显卡评测-中关村在线
  10. 解决Ubuntu下任务栏不显示任务的问题
  11. 报告格式调整(自动生成目录、页码设置等)
  12. python 获取股票的交易数据
  13. 压力测试软件 loadr,初学abench压力测试 - 玄大冰 - 51Testing软件测试网 51Testing软件测试网-软件测试人的精神家园...
  14. 【汇正财经】企业资本的意义
  15. 2021年高考安庆10中成绩查询,2021年安庆高中学校排名及录取分数线排名
  16. 翻出2018的Java84班的二阶段项目-商城项目
  17. 风影导航源码 带后台
  18. 云队友丨稻盛和夫:“愚直”的人,终成大器
  19. linux模仿mac os,创新or抄袭?仿苹果OS开源Pear Linux体验
  20. python画画用哪库好_Python我要学画画-turtle库

热门文章

  1. Access restriction: The type 'BASE64Encoder' is not API 的解决方法
  2. java设计模式 订阅模式_Java中的外观设计模式
  3. javafx 调用java_Java“地铁”表(JavaFX)
  4. packt_Packt发行的$ 5 Java编程书籍:精通Java 9,Java 9高性能
  5. dot2谜团png_一个类加载的谜团解决了
  6. Java和Round-Robin上的AtomicInteger
  7. kie-api_KIE-WB / JBPM控制台Ng –配置
  8. jboss eap 7.0_创建委托登录模块(用于JBoss EAP 6.1)
  9. 如何处理班级过多的问题
  10. 会java的鸭子_鸭子在Java中打字? 好吧,不完全是