Запись в 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 вы можете замаскировать номера карт.