В этой статье я расскажу, как отлаживать сгенерированный SQL Hibernate, чтобы неожиданные результаты запроса быстрее отслеживались либо в неверном наборе данных, либо в ошибке в запросе.
Больше нет необходимости представлять Hibernate. Тем не менее, для тех, кто жил в пещере в течение последних лет, скажем, что Hibernate является одной из двух основных сред ORM (второй является TopLink), которые значительно упрощают доступ к базе данных в Java.
Одна из главных целей Hibernate — уменьшить количество написанного вами SQL-кода до такой степени, что во многих случаях вы даже не будете писать ни одной строки. Однако есть вероятность, что однажды механизм извлечения Hibernate не даст вам ожидаемого результата, и проблемы начнутся всерьез. С этого момента и перед дальнейшим расследованием вы должны определить, что является правдой:
- либо исходный набор данных неверен
- или сгенерированный запрос
- или оба, если вам действительно не повезло
Возможность быстро диагностировать реальную причину отнимет у вас много времени. Для этого самым большим шагом будет просмотр сгенерированного SQL: если вы сможете выполнить его в правильном инструменте запроса, вы можете сравнить результаты чистого SQL с результатами Hibernate и установить истинную причину. Есть два решения для просмотра SQL.
Показать SQL
Первое решение является самым простым. Он является частью конфигурации Hibernate и тщательно документирован. Просто добавьте следующую строку в файл hibernate.cfg.xml:
<hibernate-configuration>
<session-factory>
...
<property name="hibernate.show_sql">true</property>
</session-factory>
</hibernate-configuration>
Предыдущий фрагмент, скорее всего, покажет что-то подобное в журнале:
выберите this_.PER_N_ID в качестве PER1_0_0_, this_.PER_D_BIRTH_DATE в качестве PER2_0_0_, this_.PER_T_FIRST_NAME в качестве PER3_0_0_, this_.PER_T_LAST_NAME в качестве PER4_0_ON_ из этого PER4_0_ON_
Не очень читаемый, но достаточно для копирования / вставки в ваш любимый инструмент запросов.
Основным недостатком этого является то, что если запрос имеет параметры, они будут отображаться как? и не будет отображать их значения, как в следующем выводе:
выберите this_.PER_N_ID в качестве PER1_0_0_, this_.PER_D_BIRTH_DATE в качестве PER2_0_0_, this_.PER_T_FIRST_NAME в качестве PER3_0_0_, this_.PER_T_LAST_NAME в качестве PER4_0_0_ из T_PERSON из этого_SER_ER_ER_ER_ER_ER_ER_ER_ER_ER_ER_ER_ER
Если у них слишком много параметров, вам будет больно, и замена каждого параметра на его значение займет слишком много времени.
Тем не менее, ИМХО, эта простая конфигурация должна быть включена во всех средах (за исключением производства), поскольку ее можно легко отключить.
Прокси драйвер
Второе решение является более навязчивым и включает сторонний продукт, но гораздо более мощный. Он состоит из помещения прокси-драйвера между JDBC и реальным драйвером, так что весь сгенерированный SQL будет зарегистрирован. Он совместим со всеми решениями ORM, основанными на архитектуре JDBC / драйвера.
P6Spy — драйвер, который делает именно это. Несмотря на свой возраст (последний релиз датируется 2003 годом), он не устарел и отлично справляется с нашей задачей. Он состоит из самого прокси-драйвера и файла конфигурации свойств (spy.properties), которые должны присутствовать в пути к классам.
Чтобы использовать функцию P6Spy, единственное, что вам нужно сделать, это указать Hibernate использовать определенный драйвер:
<hibernate-configuration>
<session-factory>
<!-- Only this line changes -->
<property name="connection.driver_class">com.p6spy.engine.spy.P6SpyDriver</property>
...
</session-factory>
</hibernate-configuration>
Это минимальный spy.properties:
module.log=com.p6spy.engine.logging.P6LogFactory
realdriver=org.hsqldb.jdbcDriver
autoflush=true
excludecategories=debug,info,batch,result
appender=com.p6spy.engine.logging.appender.StdoutLogger
Обратите внимание на параметр realdriver, чтобы P6Spy знал, куда перенаправлять вызовы.
При использовании только этого вышеприведенный вывод становится следующим:
1270906515233 | 3 | 0 | оператор | выберите this_.PER_N_ID в качестве PER1_0_0_, this_.PER_D_BIRTH_DATE в качестве PER2_0_0_, this_.PER_T_FIRST_NAME в качестве PER3_0_0_, this_.PER_T_ATE__T_0_0_0_0_0_0_0_0_0_0_0_0_0_0_0_0_0_2_0_0_0_0_0_0_0_0_0_0_2_0_2_0_2_0_2_0_0_0_0_0_2_0_0_0_0_0_0_0_0_2_ к_БРОБЕЛИ_ИГР ? и this_.PER_T_FIRST_NAME = и this_.PER_T_LAST_NAME =) |? выберите this_.PER_N_ID в PER1_0_0_, this_.PER_D_BIRTH_DATE как PER2_0_0_, this_.PER_T_FIRST_NAME в PER3_0_0_, this_.PER_T_LAST_NAME в PER4_0_0_ из T_PERSON this_ где (this_.PER_D_BIRTH_DATE = ‘2010 -04-10 ‘и this_.PER_T_FIRST_NAME =’ Джонни ‘и this_.PER_T_LAST_NAME =’ Будь хорошим ‘)
Конечно, конфигурация может пойти дальше. Например, P6Spy знает, как перенаправить журналы в файл или в Log4J (в настоящее время он не использует адаптер SLF4J, но любой может легко его кодировать).
Если вам нужно использовать P6Spy на сервере приложений, настройку следует выполнить на самом сервере приложений на уровне источника данных. В этом случае будет отслеживаться каждое использование этого источника данных, будь то Hibernate, TopLink, iBatis или просто старый JDBC.
Например, в Tomcat поместите spy.properties в common / classes и обновите конфигурацию источника данных, чтобы использовать драйвер P6Spy.
Исходный код этой статьи можно найти здесь .
Чтобы идти дальше:
- P6Spy официальный сайт
- Log4jdbc , претендент на Google Code, который стремится предложить те же функции