Запись в PreparedStatements в Java

Одной вещью, которая всегда была боль, является регистрация ошибок SQL (JDBC), когда у вас есть PreparedStatement, а не сам запрос.

Вы всегда получаете сообщения вроде:

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.

Спасибо!

Ответ 1

Я попробовал log4jdbc, и он выполнил эту работу для меня.

ПРИМЕЧАНИЕ БЕЗОПАСНОСТИ: На сегодняшний день в августе 2011 года зарегистрированные результаты подготовленного оператора log4jdbc НЕ БЕЗОПАСНЫ для выполнения. Они могут использоваться для анализа, но НИКОГДА не должны возвращаться в СУБД.

Пример журнала, сгенерированного 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, бар, DRINK_ID, СУММА, ОПИСАНИЕ, СТАТУС, code2, REJECT_DESCR, ID_CUST_REJ) ЗНАЧЕНИЯ (2, '123', 1, '2', 'аа', 'страх', 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, но все же полезно.
Из того, что я пробовал, если вы установили

Вы получите только инструкции, но я не знаю, влияет ли эта библиотека на производительность.

Ответ 2

Это очень зависит от базы данных. Например, я понимаю, что некоторые драйверы JDBC (например, sybase, возможно, ms-sql) обрабатывают подготовленные операторы, создавая временную хранимую процедуру на сервере и затем вызывая эту процедуру с предоставленными аргументами. Таким образом, полный SQL никогда не передается от клиента.

В результате API JDBC не предоставляет вам информацию. Возможно, вы сможете указать объекты своих утверждений на внутреннюю реализацию драйвера, но, вероятно, нет - ваш сервер приложений вполне может переносить утверждения в свою собственную реализацию.

Я думаю, вам просто нужно будет укусить пулю и написать свой собственный класс, который интерполирует аргументы в SQL-заполнителя. Это будет неудобно, потому что вы не можете запросить PreparedStatement для параметров, которые были установлены, поэтому вам придется запомнить их в вспомогательном объекте, прежде чем передавать их в оператор.

Мне кажется, что одна из библиотек-утилит, которые обертывают ваши объекты реализации драйвера, является наиболее практичным способом делать то, что вы пытаетесь достичь, но это будет неприятно в любом случае.

Ответ 3

Используйте P6Spy: его Oracle, Mysql, JNDI, JMX, Spring и Maven. Высокая конфигурация. Простая и низкая интеграция Можно распечатать stacktrace. Можно печатать только тяжелые вызовы - время на основе threashold.

Ответ 4

  • Если вы используете MySQL, MySQL Connector PreparedStatement.toString() содержит связанные параметры. Хотя сторонние пулы соединений могут нарушить это.

  • Подкласс PreparedStatement для создания строки запроса в качестве параметров добавляется. Нет способа извлечь SQL из PreparedStatement, поскольку он использует скомпилированную двоичную форму.

LoggedPreparedStatement выглядит многообещающим, хотя я его не пробовал.

Одно из преимуществ этих прокси-драйверов, которые регистрируют все запросы, заключается в том, что вы можете изменить строку запроса перед ее записью. Например, в среде PCI вы можете замаскировать номера карт.