【问题标题】:EJB3 Getting at original JDBC ErrorsEJB3 处理原始 JDBC 错误
【发布时间】:2010-12-03 13:52:24
【问题描述】:

我使用默认的 TopLink 持久性管理器在 Glassfish 上使用 EJB3。在会话 Bean 中,当持久性管理器捕获 DB 异常时,它会将事务标记为回滚,并抛出 EJBException,进而包装 RollbackException。现在我期望能够从这些异常之一的异常中得到原始的 jdbc 异常,但事实并非如此。

检索原始异常很重要,因为我需要向用户报告问题所在,为此我需要分析 SQL 错误代码。

有谁知道是否可以从 Toplink 获得这些信息?或者 Hibernate 是否使之成为可能?

谢谢,

【问题讨论】:

    标签: java hibernate glassfish ejb-3.0 toplink


    【解决方案1】:

    我有同样的问题。我最终使用了 AroundInvoke 拦截器方法,这样您就可以在服务器端捕获任何异常,并提取您想要的任何信息并将其包装以引发您自己的异常,并设置 EjbContext 以回滚事务。

    如果你不正确,我可以给你举个例子。

    【讨论】:

    • 我以前没有遇到过拦截器,但刚刚对它们进行了一些阅读,它看起来像是我想要的那种东西。但是,看起来我可以为业务方法和生命周期事件定义拦截器,但这些似乎都不是我想要的,因为我想要拦截的方法在 EntityManager 中。多指点,不胜感激!
    【解决方案2】:

    好问题,蚂蚁

    我知道您想抛出一个数据库异常,但是当它发生时,应用程序在大多数情况下无法恢复其初始状态,或者它不知道如何从中恢复。所以它应该作为运行时异常处理。数据库异常中的一些问题包括

    • 数据库连接失败
    • 查询错误
    • 表或列不存在

    您在上面看到的应用程序无法恢复其初始状态。如果您认为可以恢复其初始状态那么您应该使用应用程序异常。客户端将获得您的业务方法引发的相同应用程序异常。如果您希望能够获得业务方法抛出的确切异常,您有两种选择:

    • 使用业务委托模式访问您的 EJB

    如您所知,运行时异常由 EJBException 包装,因此您应该使用类似

    假设你有这个无状态会话 bean

    @Stateless
    public class BeanImpl implements Bean {
    
        public void doSomething() {
    
            try {
                // some code
            } catch(SomeException e) {
                throw new EJBException(e);
            }
    
        }        
    
    }
    

    所以你通过一个业务委托来包装你的会话 bean

    public class BeamBusinessDelegate implements Bean {
    
        // your stateless session bean goes here
        private Bean bean;
    
        public BeamImpl() {
            InitialContext i = new InitialContext();
    
            bean = (Bean) i.lookup(<GLOBAL_JNDI_ADDRESS_OR_RELATIVE_ENVIRONMENT_NAMING_CONTEXT_ADDRESS>);
        }
    
        public void doSomething() {
            try {
                bean.doSomething()
            } catch(EJBException e) {
                throw e.getCause();
            }
        }
    }
    

    或者您可以根据需要扩展 EJBException

    public class DatabaseException extends EJBException {
    
    }
    

    所以在你的商业方法中

    @Stateless
    public class BeanImpl implements Bean {
    
        public void doSomething() {
    
            try {
                // some code
            } catch(SomeException e) {
                throw new DatabaseException();
            }
    
        }        
    
    }
    

    问候,

    【讨论】:

    • 嗨 - 感谢您的回复。您的示例几乎准确地展示了我们已经在做的事情。我想你误解了我的问题。问题在于,Glassfishes 默认的持久性管理器 Toplink 没有在 EJBException 的“原因”字段中包含原始原因。所以我的问题真的是,有没有办法让 Toplink 正确地包含原因,或者 Hibernate 做得更好吗?
    • 哦 - 而且看起来还不清楚是不是我的代码引发了异常 - 我们正在使用实体 Beans 来持久化数据,并且是持久性管理器抛出EJBException 包装了一个没有设置原因的 RolledbackException。
    • Ant,JPA 是 JDBC 之上的更高层次的抽象。我认为您无法访问底层 JBDC 层。在看到 PersistenceException - oracle.com/technology/products/ias/toplink/jpa/resources/… - Java Persisntece API 的根异常后,它没有为您提供访问底层 JDBC 层的方法,所以我认为这是不可能的。
    • 谢谢 Arthur - ChristiaanP 有一个看起来很有希望的领先优势,我将在上面尝试。我不敢相信没有办法获得这些信息,因为如果你想成功处理或报告持久化或合并中的错误,SQL 错误代码是必不可少的。
    【解决方案3】:

    我发现做我想做的唯一方法是强制管理器使用 manager.flush() 写入数据库,然后捕获抛出的 PersistenceException。然后我可以根据需要记录数据库错误,并抛出 EJBException 以强制回滚。离开容器进行刷新似乎无法挽回地丢失 TopLink 的任何有用消息。

    【讨论】:

    • 我也有同样的问题,你能用代码示例编辑你的答案吗?
    【解决方案4】:

    我也有同样的问题:如何获取 JPA 生成的 SQL 错误消息?

    我也没有找到解决方案,但是我在我的 persistence.xml 中添加了这一行

        <properties>
            <property name="toplink.logging.level" value="FINE" />
        </properties>
    

    现在,我可以看到发出的 sql 命令了。

    参考: http://www.jairrillo.com/blog/2008/09/04/introduction-to-jpa-part-1-getting-started/

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2010-10-14
      • 1970-01-01
      • 2022-09-24
      • 1970-01-01
      • 2012-01-08
      • 2020-12-24
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多