Существует два хорошо известных способа входа в Hibernate SQL в Grails; Одним из них является добавление logSql = true в DataSource.groovy (либо в блоке верхнего уровня для всех сред, либо для каждой среды).
|
1
2
3
4
5
6
|
dataSource { dbCreate = ... url = ... ... logSql = true} |
а другой должен использовать конфигурацию регистрации Log4j:
|
1
2
3
4
|
log4j = { ... debug 'org.hibernate.SQL'} |
Проблема с logSql том, что это слишком просто — он просто сбрасывает SQL в stdout, и нет возможности увидеть значения, которые устанавливаются для позиционного ? параметры. Подход к ведению журнала гораздо более настраиваемый, поскольку вы можете войти в консоль, если хотите, но вы можете настроить ведение журнала в файл, в файл только для этих сообщений или в любое место по вашему выбору с помощью Appender .
Но подход к ведению журнала тоже проблематичен — благодаря включению второй категории Log4j
|
1
2
3
4
5
|
log4j = { ... debug 'org.hibernate.SQL' trace 'org.hibernate.type'} |
мы можем видеть значения переменных, но вы видите их как для наборов PreparedStatement и для результатов ResultSet , и результаты могут привести к большим файлам журналов, полным бесполезных операторов. Это работает, потому что классы «Тип», которые Hibernate использует для хранения и загрузки значений классов Java в столбцы базы данных (например, LongType , StringType и т. Д.), Находятся в пакете org.hibernate.type и расширяют (косвенно) org.hibernate.type.NullableType который выполняет регистрацию в своих nullSafeSet и nullSafeGet .
Так что, если у вас есть класс домена GORM
|
1
2
3
|
class Person { String name} |
и вы сохраняете экземпляр
|
1
|
new Person(name: 'me').save() |
вы увидите вывод так:
|
1
2
3
4
|
DEBUG hibernate.SQL - insert into person (id, version, name) values (null, ?, ?)TRACE type.LongType - binding '0' to parameter: 1TRACE type.StringType - binding 'me' to parameter: 2DEBUG hibernate.SQL - call identity() |
Когда вы позже запустите запрос, чтобы получить один или несколько экземпляров
|
1
|
def allPeople = Person.list() |
вы увидите вывод, как это
|
1
2
3
4
|
DEBUG hibernate.SQL - select this_.id as id0_0_, this_.version as version0_0_, this_.name as name0_0_ from person this_TRACE type.LongType - returning '1' as column: id0_0_TRACE type.LongType - returning '0' as column: version0_0_TRACE type.StringType - returning 'me' as column: name0_0_ |
Это неплохо для одного экземпляра, но если бы было несколько результатов, у вас был бы блок для каждого результата, содержащий строку для каждого столбца.
Я говорил об этом вчера на своем выступлении в Hibernate на SpringOne 2GX и понял, что должна быть возможность создать собственный Appender который проверяет операторы журнала для этих классов и игнорирует операторы, полученные в результате получения ResultSet . К моему удивлению, в Grails 2.x все изменилось, потому что мы обновили Hibernate 3.3 до 3.6, и эта проблема уже решена в Hibernate.
Вышеприведенный вывод фактически сделан из проекта 1.3.9, который я создал после неожиданного вывода в приложении 2.1.1. Вот что я увидел в 2.1.1:
|
01
02
03
04
05
06
07
08
09
10
11
12
|
DEBUG hibernate.SQL - /* insert Person */ insert into person (id, version, name) values (null, ?, ?)TRACE sql.BasicBinder - binding parameter [1] as [BIGINT] - 0TRACE sql.BasicBinder - binding parameter [2] as [VARCHAR] - asd |
и
|
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
|
DEBUG hibernate.SQL - /* load Author */ select author0_.id as id1_0_, author0_.version as version1_0_, author0_.name as name1_0_ from author author0_ where author0_.id=?TRACE sql.BasicBinder - binding parameter [1] as [BIGINT] - 1TRACE sql.BasicExtractor - found [0] as column [version1_0_]TRACE sql.BasicExtractor - found [asd] as column [name1_0_] |
Так что теперь вместо того, чтобы делать всю регистрацию из базового класса типов, он был переработан для делегирования org.hibernate.type.descriptor.sql.BasicBinder и org.hibernate.type.descriptor.sql.BasicExtractor . Это здорово, потому что теперь мы можем изменить конфигурацию Log4j на
|
1
2
3
4
5
|
log4j = { ... debug 'org.hibernate.SQL' trace 'org.hibernate.type.descriptor.sql.BasicBinder'} |
и есть наш торт и есть его тоже; SQL регистрируется в настраиваемом месте назначения Log4j, и регистрируются только наборы PreparedStatement .
Обратите внимание, что во втором примере SQL выглядит по-разному не из-за изменений в Grails или Hibernate, а потому, что я всегда format_sql форматирование SQL (с format_sql ) и комментарии (с use_sql_comments ) в тестовых приложениях, поэтому, когда я use_sql_comments ведение журнала, он оказывается более читаемый, и я забыл сделать это для приложения 1.3:
|
1
2
3
4
5
6
7
|
hibernate { cache.use_second_level_cache = true cache.use_query_cache = false cache.region.factory_class = 'net.sf.ehcache.hibernate.EhCacheRegionFactory' format_sql = true use_sql_comments = true} |
Ссылка: ведение журнала Hibernate SQL от нашего партнера по JCG Берта Беквита в блоге « Армия солипсистов» .