如何從Oracle, MySql, PostgreSQL的PreparedStatement獲得所執行的sql語句?


一、問題提出

從且只從一個PreparedStatement中獲取執行的sql語句(包括運行時綁定的參數值),是實際工作中經常遇到的一個問題。

網上很多文章提到用自定義的增強類或中間件(p6spy, log4jdbc)來實現,但這需要對現有代碼進行修改,工作量很大,能不能有更直接的辦法?

由於java.sql.PreparedStatement並沒有提供相應接口,此功能是否實現及如何實現,不同數據庫的JDBC是不一樣的。PostgreSQL和MySQL的DBC用toString接口實現了此功能;但對於Oracle,問題比較棘手。

二、PostgreSQL和MySQL

PostgreSQL和MySQL可以直接使用toString接口獲取sql,且會得到綁定的參數值。兩者的區別在於:MySQL會在前面加上類名。

    PreparedStatement ps = con.prepareStatement("SELECT value from sys_param where name=?");
    ps.setString(1, "UNIT_CODE");
    System.out.println(ps.toString());

PostgreSQL的輸出是:SELECT value from sys_param where name='UNIT_CODE',可以直接使用。

MySQL的輸出是:com.mysql.cj.jdbc.ClientPreparedStatement: SELECT value from sys_param where name='UNIT_CODE',此時,只需將“: ”前部分截斷即可。

但Oracle的輸出則是:oracle.jdbc.driver.OraclePreparedStatementWrapper@7b98f307,無法使用。

三、Oracle

經過仔細分析Oracle JDBC的類,發現oracle.jdbc.internal.OraclePreparedStatement(注意不能是oracle.jdbc.OraclePreparedStatement)提供了一個接口getOriginalSql()。用它進行嘗試:

    PreparedStatement ps = con.prepareStatement("SELECT value from sys_param where name=?");
    ps.setString(1, "UNIT_CODE");
    if (ps instanceof OraclePreparedStatement) {
        OraclePreparedStatement ops = (OraclePreparedStatement)ps;
        System.out.println(ops.getOriginalSql());
    }

輸出是:SELECT value from sys_param where name=?,只差綁定的參數值了。

那么,能不能進一步將綁定參數也解析出來?從目前掌握的信息看,Oracle還做不到。

四、通用方法

根據以上,可以構造一個從PreparedStatement獲取sql的通用方法,如下:

public String getSql(PreparedStatement ps) throws SQLException
{
    if (ps==null || ps.getConnection()==null)
        return null;
switch (ps.getConnection().getMetaData().getDatabaseProductName().toUpperCase())
    {
    case "ORACLE":
        OraclePreparedStatement ops = (OraclePreparedStatement)ps;
        return ops.getOriginalSql();
    case "MYSQL":
        String temp = ps.toString();
        return temp.substring(temp.indexOf(':') + 1);
    case "POSTGRESQL":
        return ps.toString();
    }
    return ps.toString();
}

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM