天天看点

PrepareStatement 如何打印真实 SQL

我们知道,JDBC 的 PrepareStatement 优点多多,通常都是推荐使用 PrepareStatement 而不是其基类 Statment。PrepareStatement 支持 ? 占位符,可以将参数按照类型转自动换为真实的值。既然这一过程是自动的,封装在 JDBC 内部的,那么我们外部就不得而知目标的 SQL 最终生成怎么样——于是在调试过程中便有一个打印 SQL 的问题。我们对 PrepareStatement 传入 SQL 语句,如 SELECT * FROM table WHERE id = ?,然后我们传入对应的 id 参数,假设是 id = 10,那怎么把得到参数的 SELECT * FROM table WHERE id =  12 结果完整地得出来呢?——这便是本文所要探讨的问题。

首先,我们看看典型的一个 PrepareStatement 调用方法,如下一个函数,

值得注意该函数里面:

其参数一 sql 就是类似 SELECT * FROM table WHERE id = ? 的语句,参数二 params 为 Object... params 的参数列表,可以是任意类似的合法 SQL 值。最后,通过 printRealSql 函数最终得出形如 SELECT * FROM table WHERE id =  12 的结果。

printRealSql 函数源码如下:

可见,上述思路是非常简单的,——有多少个 ? 占位符,就要求有多少个参数,然后一一对照填入(数组)。match 函数会检查第一个步骤,检查个数是否匹配,否则会返回“SQL 语句中的占位符与参数个数不匹配”的提示;然后,参数的值会被转换为符合 SQL 值所要求的类型;最后,就是将 SQL 一一填入,——此处使用了一个字符串的技巧,先把 ? 字符通通转换为 %s,——那是 String.format 可识别的占位符,如此再传入 Object[] 参数列表,即可得出我们期待的 SQL 结果。

我们不能保证那 SQL 可以直接放到数据库中被解析。因为我们的初衷只是把 SQL 打印出来,务求更近一步让程序员在开发阶段看到 SQL 是怎么样子的,而且不是一堆 ?、?……,这样会显得更符合真实情形一点。

PrepareStatement 内部源码肯定有这一步骤或者某个变量是表示那个真实 SQL 的,——只是没有暴露出来。如果有,那么对程序员会更友好一些。