六安网站建设电话,html5视频播放器插件,wordpress 页面内分页,微信平台开发公司成都jpa 异常捕获使用CMT#xff08; 容器管理的事务 #xff09;进入EJB和JPA的世界非常舒适。 只需定义一些注释来划分事务边界#xff08;或使用默认值#xff09;即可#xff0c;仅此而已–无需摆弄手动开始#xff0c;提交或回滚操作。 回滚事务的一种方法是从EJB的业务… jpa 异常捕获 使用CMT 容器管理的事务 进入EJB和JPA的世界非常舒适。 只需定义一些注释来划分事务边界或使用默认值即可仅此而已–无需摆弄手动开始提交或回滚操作。 回滚事务的一种方法是从EJB的业务方法中引发非应用程序异常或具有rollback true的应用程序异常。 看起来很简单如果在某些操作过程中可能会引发异常并且您不想回滚tx那么您应该捕获该异常就可以了。 现在您可以在同一仍处于活动状态的事务中再次重试该易失性操作。 现在对于从用户组件抛出的应用程序异常这一切都是正确的 。 问题是– 除了其他组件引发的异常之外还有什么 就像JPA的EntityManager抛出PersistenceException 这就是故事的开始。 我们想要实现的目标 设想以下情形您有一个名为E的实体。它包含 id –这是主键 名称 -这是一些易于理解的实体名称 内容 –包含字符串的任意字段–它模拟“高级属性”例如在持久性/合并期间进行计算会导致错误。 代码 –包含OK或ERROR字符串–定义高级属性是否成功持久保存 您要持久化E。您假定E的基本属性将始终被成功持久化。 但是高级属性需要一些额外的计算或操作这可能会导致例如从数据库引发约束冲突。 如果发生这种情况您仍然希望E保留在数据库中但仅填充基本属性并且将代码属性设置为“ ERROR”。 换句话说这是您可能想到的 坚持E的基本属性 尝试使用脆弱的高级属性对其进行更新 如果从步骤2抛出了PersistenceException捕获它将code属性设置为“ ERROR”并清除所有高级属性它们导致异常 更新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 dont 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 dont 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因此默认情况下为rollbackfalse 。 用于通知更新操作失败。 或者您可以更改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.htmljpa 异常捕获