Автор оригинала: Vlad Mihalcea.
Вступление
Очень полезной, но менее известной функцией Hibernate является возможность перехватывать и изменять любые автоматически сгенерированные инструкции SQL с помощью утилиты Hibernate StatementInspector
.
В этой статье мы рассмотрим, как работает механизм Hibernate Инспектор операторов
.
Инспектор по заявлениям
Инспектор операторов Hibernate | представляет собой функциональный интерфейс, который выглядит следующим образом:
Метод inspect
принимает инструкцию SQL, которая должна быть выполнена Hibernate, и позволяет вам изменить инструкцию SQL и вернуть ее в Hibernate StatementPreparer
.
Чтобы зарегистрировать реализацию интерфейса StatementInspector
в режиме гибернации, вы можете использовать свойство hibernate.session_factory.statement_inspector
конфигурации, которое может принимать объект StatementInspector
Java, Класс
или Строку
объект, определяющий класс, реализующий интерфейс StatementInspector
.
Ведение журнала и изменение инструкций SQL Hibernate
Чтобы лучше идентифицировать инструкции SQL, создаваемые Hibernate, мы можем использовать свойство конфигурации hibernate.use_sql_comments
.:
Таким образом, при сохранении Книги
сущности:
entityManager.persist( new Book() .setIsbn("978-9730228236") .setTitle("High-Performance Java Persistence") .setAuthor("Vlad Mihalcea") );
Hibernate создает следующую инструкцию SQL:
/* insert com.vladmihalcea.book.hpjp.hibernate.logging.inspector.Book */ INSERT INTO book ( author, isbn, title, id ) VALUES ( 'Vlad Mihalcea', '978-9730228236', 'High-Performance Java Persistence', 1 )
Обратите внимание на комментарий SQL, в котором говорится, что инструкция INSERT связана с операцией Книга
сохранение сущности.
При извлечении Книги
сущности по ее естественному идентификатору :
Book book = entityManager .unwrap(Session.class) .bySimpleNaturalId(Book.class) .load("978-9730228236");
Hibernate создает следующие инструкции SQL:
/* get current natural-id -> entity-id state com.vladmihalcea.book.hpjp.hibernate.logging.inspector.Book */ SELECT book_.id as id1_0_ FROM book book_ WHERE book_.isbn = '978-9730228236' SELECT book0_.id as id1_0_0_, book0_.author as author2_0_0_, book0_.isbn as isbn3_0_0_, book0_.title as title4_0_0_ FROM book book0_ WHERE book0_.id = 1
Первая инструкция SQL SELECT предназначена для разрешения идентификатора сущности на основе предоставленного естественного идентификатора, как объясняется в соответствующем комментарии SQL.
Второй запрос предназначен для извлечения сущности Book
на основе разрешенного идентификатора сущности.
Хотя комментарии SQL могут предоставить полезный контекст для автоматически создаваемых SQL-запросов, комментарий отправляется на сервер базы данных, что увеличивает пропускную способность сети и мешает механизму кэширования инструкций SQL.
По этой причине мы хотели бы зарегистрировать инструкцию SQL вместе с контекстом, зависящим от Hibernate, убедившись, что комментарий SQL удаляется до выполнения инструкции SQL.
Ведение журнала и изменение операторов SQL с помощью инспектора операторов
Следующая реализация Инспектора операторов
позволяет нам регистрировать инструкцию SQL вместе с контекстом, зависящим от режима гибернации, а также удалять комментарий SQL из инструкции до ее возврата.
public class SqlCommentStatementInspector implements StatementInspector { private static final Logger LOGGER = LoggerFactory .getLogger( SqlCommentStatementInspector.class ); private static final Pattern SQL_COMMENT_PATTERN = Pattern .compile( "\\/\\*.*?\\*\\/\\s*" ); @Override public String inspect(String sql) { LOGGER.debug( "Executing SQL query: {}", sql ); return SQL_COMMENT_PATTERN .matcher(sql) .replaceAll(""); } }
Инспектор операторов комментариев Sql
может быть предоставлен для перехода в режим гибернации с помощью свойства конфигурации hibernate.session_factory.statement_inspector|/.
Теперь при сохранении сущности Book
Hibernate создает следующую запись в журнале и выполняет инструкцию SQL без комментария SQL:
-- Executing SQL query: /* insert com.vladmihalcea.book.hpjp.hibernate.logging.inspector.Book */ insert into book (author, isbn, title, id) values (?, ?, ?, ?) Query:["insert into book (author, isbn, title, id) values (?, ?, ?, ?)"], Params:[(Vlad Mihalcea, 978-9730228236, High-Performance Java Persistence, 1)]
И то же самое касается извлечения сущности Book
по ее естественному идентификатору:
-- Executing SQL query: /* get current natural-id->entity-id state com.vladmihalcea.book.hpjp.hibernate.logging.inspector.Book */ select book_.id as id1_0_ from book book_ where book_.isbn=? Query:["select book_.id as id1_0_ from book book_ where book_.isbn=?"], Params:[(978-9730228236)] -- Executing SQL query: select book0_.id as id1_0_0_, book0_.author as author2_0_0_, book0_.isbn as isbn3_0_0_, book0_.title as title4_0_0_ from book book0_ where book0_.id=? Query:["select book0_.id as id1_0_0_, book0_.author as author2_0_0_, book0_.isbn as isbn3_0_0_, book0_.title as title4_0_0_ from book book0_ where book0_.id=?"], Params:[(1)]
Круто, правда?
Вывод
Инспектор операторов
– это очень мощный механизм, который позволяет перехватывать все инструкции SQL в режиме гибернации и решать, хотите ли вы изменять инструкции до их выполнения.