Java EJB3获取原始JDBC错误

Java EJB3获取原始JDBC错误,java,hibernate,glassfish,ejb-3.0,toplink,Java,Hibernate,Glassfish,Ejb 3.0,Toplink,我使用默认的TopLink持久性管理器在Glassfish上使用EJB3。在会话Bean中,当持久性管理器捕获到一个DB异常时,它会标记要回滚的事务,并抛出一个EJBException,然后包装一个回滚异常。现在我希望能够从其中一个异常的由异常引起的异常中获取原始jdbc异常,但事实并非如此 检索原始异常非常重要,因为我需要向用户报告问题所在,为此我需要分析SQL错误代码 有人知道是否有可能从Toplink获得此信息吗?或者冬眠是否使之成为可能 谢谢,好问题,Ant 我知道您想抛出数据库异常,但

我使用默认的TopLink持久性管理器在Glassfish上使用EJB3。在会话Bean中,当持久性管理器捕获到一个DB异常时,它会标记要回滚的事务,并抛出一个EJBException,然后包装一个回滚异常。现在我希望能够从其中一个异常的由异常引起的异常中获取原始jdbc异常,但事实并非如此

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

有人知道是否有可能从Toplink获得此信息吗?或者冬眠是否使之成为可能

谢谢,好问题,Ant

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

  • 数据库连接失败
  • 这个疑问是错误的
  • 表或列不存在
上面您可以看到应用程序无法恢复其初始状态。如果您认为可以恢复其初始状态,则应使用应用程序异常。客户端将获得与您的业务方法相同的应用程序异常。如果您希望能够获得业务方法引发的确切异常,您有两个选择:

  • 使用业务委托模式访问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();
        }
    }
}
所以在你的商业方法中

@Stateless
public class BeanImpl implements Bean {

    public void doSomething() {

        try {
            // some code
        } catch(SomeException e) {
            throw new DatabaseException();
        }

    }        

}

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


如果你做得不对,我可以给你举个例子。

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

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

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

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

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

参考:

您好-谢谢您的回复。你的例子非常准确地说明了我们已经在做什么。我想你误解了我的问题。问题在于,默认的持久性管理器Toplink在EJBException的“原因”字段中不包含原始原因。所以我的问题是,有没有办法让Toplink正确地包含原因,或者Hibernate做得更好呢?哦-而且看起来还不清楚引发异常的不是我的代码-我们正在使用实体bean来持久化数据,持久性管理器抛出EJBException,该EJBException封装了一个RolledbackException,该异常没有其原因集。我认为您无法访问底层JBDC层。在看到PersistenceException——Java Persisntece API的根异常之后,它并没有为您提供访问底层JDBC层的方法,所以我认为这是不可能的。感谢Arthur-ChristiaanP有一个看起来很有希望的线索,我将在上面尝试。我不敢相信没有办法获得这些信息,因为如果您想成功地处理或报告持久化或合并中的错误,SQL错误代码是必不可少的。我以前没有遇到过拦截器,但只是对它们进行了一些阅读,这看起来正是我想要的。然而,看起来我可以为业务方法和生命周期事件定义拦截器,但这两个似乎都不是我想要的,因为我想要拦截的方法在EntityManager中。我们将非常感激地接受更多的建议!我有同样的问题,你能用代码样本编辑你的答案吗?
    <properties>
        <property name="toplink.logging.level" value="FINE" />
    </properties>