【问题标题】:How do I get at the sql statement that caused an SQLException using the Postgres JDBC driver in Java?如何使用 Java 中的 Postgres JDBC 驱动程序获取导致 SQLException 的 sql 语句?
【发布时间】:2010-10-20 18:01:57
【问题描述】:

背景

在我当前的项目中——一个没有 GUI 前端的服务器产品,我正在尝试编写更好的错误处理支持。当前错误会输出到日志中,并且通常不会被用户读取。

我们使用 PostgreSQL 作为我们的数据库后端,并通过数据库池使用直接 JDBC 调用和 DAO 来访问它。大多数与数据库相关的异常都包装在一个通用的DatabaseException 类中,该类实现了RuntimeException,并尝试从传递的异常中提取调试和状态信息。在我们的特殊情况下,它将访问底层 PostgreSQL 数据库驱动程序 - PSQLException。到目前为止,这种方法在获取有关导致数据库错误的原因的更详细信息方面效果很好,下面描述了一个明显的例外。

此外,由于我们有非常具体的性能和遗留支持要求,我们有很多自定义 SQL magic,这使得跟踪堆栈跟踪需要更多时间但并非不可能或困难。

问题描述

我注意到当我们得到一个SQLException 作为错误的 SQL 语句的结果时,驱动程序的实现不会返回导致错误的 SQL 语句。经过一番搜索,我发现有一种方法可以在启动时将 PostgreSQL 驱动程序置于调试模式,并让它显示有关其内部查询的属性。但是,我们不希望在生产环境中以调试模式运行驱动程序(老实说,我一直无法弄清楚如何让它进入怪异模式!)。

问题

之前有没有其他人处理过同样的问题并找到了解决方案?如果没有,是否有一些 OOP 模式用于在执行之前存储查询信息,然后将该信息分配给引发的异常?还是大多数开发人员只是觉得他们不需要完整的查询来解决数据库问题?老实说,我不需要它,因为我有完整的堆栈跟踪,我可以查找调用查询,但它肯定会加快我的调试速度,因为它是我在错误日志。

【问题讨论】:

    标签: java exception postgresql jdbc exception-handling


    【解决方案1】:

    我假设当您调用执行查询时,您拥有该语句,并且您收到了异常,所以此时您拥有两者。看来您可以在那里进行分析。

    但是,也许您正在进一步了解情况。所以,你可以做的是在你自己的自定义异常子类 DatabaseException 上,添加一个带有 getter 和 setter 的 triggeringSQLStatement 成员,然后在你尝试执行语句的地方,从 PostgreSQL 捕获原始异常,创建一个新的DatabaseException,将triggeringSQLStatement设置为你刚刚执行的语句,并在DatabaseException上调用initCause()将PostgreSQL捕获的异常设置为你的异常原因;然后抛出你的 DatabaseException 和捕获它的调用代码将有一个对象打印出一个非常体面的堆栈跟踪所发生的事情,并提供对导致问题的 SQL 语句的访问。有关此方法的更多信息,您可能需要研究 Java 异常链接。即使您没有使用我刚刚描述的所有内容,我认为您肯定应该已经在使用 Java 异常链接了。

    如果代码中没有任何地方可以访问导致问题的 SQL 语句和引发的异常,我会很好奇为什么,以及这是如何实现的。我建议你重新设计你的代码,这样你就有了这样的位置。

    编辑:由于您希望首先在日志中查看 SQL 语句,因此您可能还可以覆盖 DatabaseException 的 toString() 方法(或其他适当的方法;我不确定打印出异常时调用的内容)以打印出包含的 SQL 语句,假设您按照我上面的描述包含了它。

    【讨论】:

      【解决方案2】:

      另一个监视您正在执行的查询的解决方案是pgFouine,它分析和报告 Postgres 生成的日志

      【讨论】:

        【解决方案3】:

        我认为最简单的方法是使用第三方产品,例如 p6spy。它位于您的 jdbc 驱动程序和数据库之间,并报告正在运行的确切查询。它很容易按需运行,因为它是作为另一个 JDBC 驱动程序实现的,它将委托给您的实际 JDBC 驱动程序。非常强大的工具,我无法想象没有它。

        http://www.p6spy.com/

        【讨论】:

          【解决方案4】:

          stacktrace 可以将您指向导致问题的 DAO 方法,不是吗?

          注释后编辑:如果您的 SQL 查询很复杂并且是从代码的前面部分动态生成的,那么您可以在执行这些语句之前记录(级别 TRACE 或 DEBUG)这些语句。在日志记录配置中,您可以仅为 DAO 启用日志。

          【讨论】:

          • 对于 DAO 方法,这种方法效果很好。然而,在我们通过 JDBC 调用的一些更复杂的 SQL 语句的情况下,它有点复杂,因为我们得到了执行方法的跟踪,然后我们必须回到定义语句/准备的位置。
          【解决方案5】:

          为什么不在所有 JDBC 调用 (log4j) 周围添加一个文件记录器?

          每当您进行 SQL 调用时,您都会记录 SQL 以及执行所需的时间。简单的东西。

          我们对外部系统的任何调用都这样做,例如SOAP 调用、RMI、Corba 等。它几乎每天都被证明是无价的,如果它影响性能.. 我没有注意到!

          如果您有安全问题,即不希望它进入客户端机器上的日志文件,您可以使用 SocketAppender 并将其发送到远程机器以进行集中记录。这不会完全安全,但会阻止随意的窥探者。

          【讨论】:

            【解决方案6】:

            我曾经在我的客户异常对象中添加 SQL 查询,只要有 SQLException。在我在日志文件中记录异常详细信息的代码中,我也曾经记录过 SQL。

            【讨论】:

            • 最好也记录参数。 +1
            猜你喜欢
            • 2011-11-03
            • 2013-02-17
            • 1970-01-01
            • 2018-06-29
            • 1970-01-01
            • 1970-01-01
            • 2018-02-12
            • 1970-01-01
            • 2019-08-17
            相关资源
            最近更新 更多