2011-01-14 18 views
15

SQLExceptionの汎用ロガーを作成していますが、PreparedStatementに渡されたパラメータを取得したいと思いますか?私はそれらの数を得ることができました。ボルダーからPreparedStatementからパラメータを取得するには?

ParameterMetaData metaData = query.getParameterMetaData(); 
parameterCount = metaData.getParameterCount(); 

答えて

16

短い回答:できません。

長い答え:すべてのJDBCドライバはパラメータ値をどこかに保持しますが、標準的な方法はありません。

デバッグまたは同様の目的のためにそれらを印刷したい場合、あなたはいくつかのオプションがあります:

  1. はパススルーJDBCドライバ(基礎としてp6spyまたはlog4jdbcを使用)パラメータのコピーを保持して作成します。それらを読むための公開APIを提供しています。

  2. Java Reflection API(Field.setAccessible(true)はあなたの友人です)を使用して、JDBCドライバのプライベートデータ構造を読み込みます。それが私の好みのアプローチです。私は、パラメータをデコードすることができるDB固有の実装に委譲するファクトリを持っており、それによって、getObject(int column)を介してパラメータを読み取ることができます。

  3. バグレポートを提出して、例外が改善されることを尋ねます。特にオラクルは、何が間違っているかを教えてくれるときには、本当にひどいです。

1

This articleは、DB 2 "特定" ahtoulgh、ParameterMetadataの使用の完全な例を与えます。

7

解決方法1:サブクラス

は、単にその代表者、元のプリペアドステートメントにすべてのコールを、唯一のsetObjectにコールバックを追加する、などの方法のPreparedStatementのカスタム実装を作成します。例:

public PreparedStatement prepareStatement(String sql) { 
     final PreparedStatement delegate = conn.prepareStatement(sql); 
     return new PreparedStatement() { 
      // TODO: much more methods to delegate 

      @Override 
      public void setString(int parameterIndex, String x) throws SQLException { 
       // TODO: remember value of X 
       delegate.setString(parameterIndex, x); 
      } 
     }; 
    } 

あなたはパラメータを保存し、後でそれを取得したい場合は、そこに多くのソリューションがありますが、私はマップ内のパラメータを持っているParameterAwarePreparedStatementのように新しいクラスを作成することを好みます。構造は次のように考えられます。

public class ParameterAwarePreparedStatement implements PreparedStatement { 
    private final PreparedStatement delegate; 
    private final Map<Integer,Object> parameters; 

    public ParameterAwarePreparedStatement(PreparedStatement delegate) { 
     this.delegate = delegate; 
     this.parameters = new HashMap<>(); 
    } 

    public Map<Integer,Object> getParameters() { 
     return Collections.unmodifiableMap(parameters); 
    } 

    // TODO: many methods to delegate 

    @Override 
    public void setString(int parameterIndex, String x) throws SQLException { 
     delegate.setString(parameterIndex, x); 
     parameters.put(parameterIndex, x); 
    } 
} 

解決方法2:動的プロキシ

この第二の溶液は短いですが、より多くのハックようです。

java.lang.reflect.Proxyでファクトリメソッドを呼び出し、すべての呼び出しを元のインスタンスに委任することで、ダイナミックプロキシを作成できます。例:

public PreparedStatement prepareStatement(String sql) { 
    final PreparedStatement ps = conn.prepareStatement(sql); 
    final PreparedStatement psProxy = (PreparedStatement) Proxy.newProxyInstance(ClassLoader.getSystemClassLoader(), new Class<?>[]{PreparedStatement.class}, new InvocationHandler() { 
     @Override 
     public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { 
      if (method.getName().equals("setLong")) { 
       // ... your code here ... 
      } 
      // this invokes the default call 
      return method.invoke(ps, args); 
     } 
    }); 
    return psProxy; 
} 

は、その後、あなたはメソッド名を見て、自分の価値観のための第二の方法の引数を調べることで などのsetObject、呼び出しをインターセプト。

関連する問題