JavaでのPreparedStatementsのロギング
-
03-07-2019 - |
質問
常に苦労していたことの1つは、クエリ自体ではなくPreparedStatementがある場合にSQL(JDBC)エラーをログに記録することです。
常に次のようなメッセージが表示されます:
2008-10-20 09:19:48,114 ERROR LoggingQueueConsumer-52 [Logger.error:168] Error
executing SQL: [INSERT INTO private_rooms_bans (room_id, name, user_id, msisdn,
nickname) VALUES (?, ?, ?, ?, ?) ON DUPLICATE KEY UPDATE room_id = ?, name = ?,
user_id = ?, msisdn = ?, nickname = ?]
もちろん、値を取得し、疑問符を実際の値で解析/置換するためのヘルパーメソッドを書くことができます(この質問の結果が得られない場合は、おそらくそのパスをたどります)この問題が他の誰かによって以前に解決されたかどうか、および/または私のためにそれを自動的に行う汎用ロギングヘルパーがあるかどうかを知るため。
いくつかの回答後に編集:
これまでに提供されたライブラリは、デバッグのためにステートメントを記録するのに適しているようです。これは間違いなく便利です。ただし、エラーが発生するたびにPreparedStatement自体(サブクラスではなく)を取得し、そのSQLステートメントをログに記録する方法を探しています。 PreparedStatementの代替実装を使用して、運用アプリを展開したくありません。
PreparedStatementのスペシャライゼーションではなく、ユーティリティクラスを探していると思います。
ありがとう!
解決
log4jdbc を試してみたところ、うまくいきました。
セキュリティ注:2011年8月現在、log4jdbc準備済みステートメントのログ結果は実行するのに安全ではありません。分析に使用できますが、DBMSにフィードバックしないでください。
logjdbcによって生成されるログの例:
2010/08/12 16:30:56 jdbc.sqlonly org.apache.commons.dbcp.DelegatingPreparedStatement.executeUpdate(DelegatingPreparedStatement.java:105) 8. A_TABLEに挿入 (ID_FILE、CODE1、ID_G、ID_SEQUENCE、REF、NAME、BAR、DRINK_ID、AMOUNT、DESCRIPTION、STATUS、CODE2、REJECT_DESCR、ID_CUST_REJ) 価値 (2、 '123'、1、 '2'、 'aa'、 'awe'、null、 '0123'、4317.95、 'Rccc'、 '0'、null、null、null)
ライブラリのセットアップは非常に簡単です:
HSQLDB を使用した構成:
jdbc.url=jdbc:log4jdbc:hsqldb:mem:sample
Oracle の場合:
jdbc.url=jdbc:log4jdbc:oracle:thin:@mybdd:1521:smt
jdbc.driverClass=net.sf.log4jdbc.DriverSpy
logback.xml:
<logger name="jdbc.sqlonly" level="DEBUG"/>
Mavenリポジトリにはないのに残念ですが、まだ便利です。
あなたが設定した場合、私が試したものから
エラーが発生するのはステートメントのみですが、このライブラリがパフォーマンスに影響を与えるかどうかはわかりません。
他のヒント
これは非常にデータベースに依存しています。たとえば、一部のJDBCドライバー(sybase、ms-sqlなど)は、サーバーで一時ストアドプロシージャを作成し、指定された引数でそのプロシージャを呼び出すことで準備済みステートメントを処理することを理解しています。したがって、完全なSQLがクライアントから実際に渡されることはありません。
その結果、JDBC APIはユーザーが求めている情報を公開しません。ステートメントオブジェクトを内部ドライバー実装にキャストできるかもしれませんが、おそらくそうではありません-アプリケーションサーバーは独自の実装でステートメントをラップするかもしれません。
箇条書きをかみ、引数をプレースホルダーSQLに補間する独自のクラスを作成する必要があると思います。 PreparedStatementに設定済みのパラメーターを要求することはできないため、これは厄介です。したがって、ステートメントに渡す前に、ヘルパーオブジェクトでそれらを覚えておく必要があります。
ドライバの実装オブジェクトをラップするユーティリティライブラリの1つは、達成しようとしていることを実行する最も実用的な方法であるように思えますが、どちらの方法でも不快になります。
P6Spy を使用:そのOracle、Mysql、JNDI、JMX、春と Maven に優しい。高度な設定が可能です。 シンプルで低レベルの統合 スタックトレースを印刷できます。 印刷できるのはヘビーコール-時間しきい値ベースです。
-
MySQLを使用している場合、MySQL ConnectorのPreparedStatement.toString() doesバインドされたパラメータを含めます。サードパーティの接続プールはこれを破るかもしれませんが。
-
パラメータが追加されたときにクエリ文字列を構築するサブクラスPreparedStatement。コンパイル済みのバイナリ形式を使用するため、PreparedStatementからSQLを抽出する方法はありません。
LoggedPreparedStatement は有望に見えますが、試していません。
すべてのクエリを記録するプロキシドライバに対するこれらの利点の1つは、記録する前にクエリ文字列を変更できることです。たとえば、PCI環境では、カード番号をマスクしたい場合があります。