GP Coder

Trang chia sẻ kiến thức lập trình Java

  • Java Core
    • Basic Java
    • OOP
    • Exception Handling
    • Multi-Thread
    • Java I/O
    • Networking
    • Reflection
    • Collection
    • Java 8
  • Design pattern
    • Creational Pattern
    • Structuaral Pattern
    • Behavior Pattern
  • Web Service
    • SOAP
    • REST
  • JPA
  • Java library
    • Report
    • Json
    • Unit Test
  • Message Queue
    • ActiveMQ
    • RabbitMQ
  • All
Trang chủ JPA Hibernate Interceptor & StatementInspector

Hibernate Interceptor & StatementInspector

Đăng vào 09/04/2020 . Được đăng bởi GP Coder . 6840 Lượt xem . Toàn màn hình

Nội dung

  • 1 Hibernate Interceptor
  • 2 Hibernate StatementInspector

Hibernate Interceptor

Hibernate Interceptor là gì?

Interceptor là một tính năng rất hữu ích cho ứng dụng để kiểm soát đối tượng với các sự kiện nhất định xảy ra bên trong Hibernate.

Một đối tượng đi qua các giai đoạn khác nhau trong lifecycle của nó. Interface Interceptor trong Hibernate cung cấp các phương thức có thể được gọi ở các giai đoạn khác nhau, để thực hiện một số nhiệm vụ được yêu cầu.

Các Interceptor được đăng ký dưới dạng callback và cung cấp các liên kết liên lạc giữa session và application của Hibernate. Với một callback như vậy, một ứng dụng có thể kiểm tra và thay đổi các thuộc tính của một đối tượng persistent trước khi nó được save, update, delete or load.

Có 2 cách để tạo một Interceptor:

  • Implement org.hibernate.Interceptor interface.
  • extend org.hibernate.EmptyInterceptor class.

Nếu không có yêu cầu đặc biệt, chúng ta nên extends class EmptyInterceptor và chỉ override các phương thức được yêu cầu.

Interface org.hibernate.Interceptor bao gồm các phương thức sau:

  • instantiate() : Phương thức này được gọi khi một lớp persistent được khởi tạo.
  • onLoad() : Phương thức này được gọ khi một đối tượng được load từ database và khởi tạo.
  • onSave() : Phương thức này được gọ khi một đối tượng được lưu.
  • onDelete() : Phương thức này được gọi khi một đối tượng bị xóa.
  • preFlush() : Phương thức này được gọi trước khi flush.
  • postFlush() : Phương thức này được gọi sau khi flush và một đối tượng đã được update trong bộ nhớ.
  • isUnsaved() : Phương thức này được gọi khi một đối tượng được truyền vào phương thức saveOrUpdate() .
  • findDirty() : Phương thức này được gọi khi phương thức flush() được gọi trên một đối tượng Session.
  • onFlushDirty() : Phương thức này được gọi khi Hibernate phát hiện ra rằng một đối tượng là dirty (tức là đã được thay đổi) trong quá trình flush.
  • Ngoài ra còn nhiều phương thức khác, các bạn tham khảo thêm Hibernate Interceptor javadoc.

Một Interceptor có thể được sử dụng ở: Session hoặc SessionFactory scope.

Ví dụ sử dụng Hibernate Interceptor

Create Interceptor


package com.gpcoder;

import com.gpcoder.entities.Tag;
import lombok.extern.log4j.Log4j2;
import org.hibernate.EmptyInterceptor;
import org.hibernate.type.Type;

import java.io.Serializable;
import java.util.Arrays;
import java.util.Iterator;

@Log4j2
public class LoggingInterceptor extends EmptyInterceptor {

    @Override
    public String onPrepareStatement(String sql) {
        log.debug("onPrepareStatement: {}", sql);
        return super.onPrepareStatement(sql);
    }

    @Override
    public boolean onSave(Object entity, Serializable id, Object[] state, String[] propertyNames, Type[] types) {
        log.debug("onSave: {}", entity);
        return super.onSave(entity, id, state, propertyNames, types);
    }

    @Override
    public void preFlush(Iterator entities) {
        log.debug("preFlush: {}", entities.next());
        super.preFlush(entities);
    }

    @Override
    public void postFlush(Iterator entities) {
        log.debug("postFlush: {}", entities.next());
        super.postFlush(entities);
    }
}

Register Interceptor

Cấu hình Interceptor ở mức Session:


Session session = sessionFactory
	.withOptions()
	.interceptor(new LoggingInterceptor() )
	.openSession();

Trường hợp muốn cấu hình Interceptor ở mức SessionFactory, nghĩa là tất cả Session đều áp dụng Interceptor này:


package com.gpcoder.utils;

import com.gpcoder.LoggingInterceptor;
import org.hibernate.SessionFactory;
import org.hibernate.boot.Metadata;
import org.hibernate.boot.MetadataSources;
import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
import org.hibernate.service.ServiceRegistry;

public class HibernateUtils {

	private static final SessionFactory sessionFactory = buildSessionFactory();

	private HibernateUtils() {
		super();
	}

	private static SessionFactory buildSessionFactory() {
		ServiceRegistry serviceRegistry = new StandardServiceRegistryBuilder() //
				.configure() // Load hibernate.cfg.xml from resource folder by default
				.build();
		Metadata metadata = new MetadataSources(serviceRegistry).getMetadataBuilder().build();
		return metadata.getSessionFactoryBuilder()
				.applyInterceptor( new LoggingInterceptor() ) // Register interceptor
				.build();
	}

	public static SessionFactory getSessionFactory() {
		return sessionFactory;
	}

	public static void close() {
		getSessionFactory().close();
	}
}

Trong trường hợp muốn đảm bảo thread-safe, chúng ta cần xác định session context trong file hibernate.cfg.xml:


<property name="current_session_context_class">org.hibernate.context.internal.ThreadLocalSessionContext</property>

Tạo lớp ứng dụng


package com.gpcoder;

import com.gpcoder.entities.Tag;
import com.gpcoder.utils.HibernateUtils;
import lombok.extern.log4j.Log4j2;
import org.hibernate.Session;
import org.hibernate.SessionFactory;

@Log4j2
public class HibernateInterceptorExample {

    public static void main(String[] args) {
        try (SessionFactory sessionFactory = HibernateUtils.getSessionFactory();
             Session session = sessionFactory
                     .withOptions()
                     .interceptor(new LoggingInterceptor()) // Register interceptor
                     .openSession();
             ) {

            session.getTransaction().begin();

            Tag tag = new Tag();
            tag.setName("Hibernate Interceptor");
            session.persist(tag);

            session.getTransaction().commit();
        }
    }
}

Output:


2020-Apr-02 22:41:38 PM [main] DEBUG com.gpcoder.LoggingInterceptor - onPrepareStatement: select nextval ('tag_id_seq')
2020-Apr-02 22:41:38 PM [main] DEBUG org.hibernate.SQL - select nextval ('tag_id_seq')
2020-Apr-02 22:41:38 PM [main] DEBUG com.gpcoder.LoggingInterceptor - onSave: Tag(id=43, name=Hibernate Interceptor)
2020-Apr-02 22:41:38 PM [main] DEBUG com.gpcoder.LoggingInterceptor - preFlush: Tag(id=43, name=Hibernate Interceptor)
2020-Apr-02 22:41:38 PM [main] DEBUG com.gpcoder.LoggingInterceptor - onPrepareStatement: insert into Tag (name, id) values (?, ?)
2020-Apr-02 22:41:38 PM [main] DEBUG org.hibernate.SQL - insert into Tag (name, id) values (?, ?)
2020-Apr-02 22:41:38 PM [main] TRACE org.hibernate.type.descriptor.sql.BasicBinder - binding parameter [1] as [VARCHAR] - [Hibernate Interceptor]
2020-Apr-02 22:41:38 PM [main] TRACE org.hibernate.type.descriptor.sql.BasicBinder - binding parameter [2] as [BIGINT] - [43]
2020-Apr-02 22:41:38 PM [main] DEBUG com.gpcoder.LoggingInterceptor - postFlush: Tag(id=43, name=Hibernate Interceptor)

Hibernate StatementInspector

Một tính năng Hibernate rất hữu ích nhưng ít được biết đến là khả năng chặn (Interceptor) và sửa đổi bất kỳ câu lệnh SQL nào được tạo tự động bằng tiện ích Hibernate StatementInspector. Trong phần tiếp theo của bài viết này, chúng ta sẽ xem cơ chế Hibernate StatementInspector hoạt động như thế nào.

Create StatementInspector

Interface StatementInspector chỉ gồm 1 phương thức duy nhất inspect(String sql). Phương thức  nhận một câu lệnh SQL mà Hibernate sắp thực hiện và cho phép bạn sửa đổi câu lệnh SQL và trả nó về Hibernate tiếp tục thực thi.

Ví dụ: tạo SqlCommentStatementInspector để remove các auto comment của Hiberate.


package com.gpcoder;

import lombok.extern.log4j.Log4j2;
import org.hibernate.resource.jdbc.spi.StatementInspector;

import java.util.regex.Pattern;

@Log4j2
public class SqlCommentStatementInspector implements StatementInspector {

    private static final Pattern SQL_COMMENT_PATTERN = Pattern.compile("\\/\\*.*?\\*\\/\\s*");

    @Override
    public String inspect(String sql) {
        log.debug("Executing SQL query: {}", sql);
        String sqlAfterRemovedComment = SQL_COMMENT_PATTERN.matcher(sql).replaceAll("");
        log.debug("After removed: {}", sqlAfterRemovedComment);
        return sqlAfterRemovedComment;
    }
}

Register StatementInspector

Để đăng ký một implment của StatementInspector, mở file hibernate.cfg.xml và thêm cấu hình sau:


<!-- Enable SQL comment -->
<property name="use_sql_comments">true</property>

<!-- egister an implementation of the StatementInspector interface -->
<property name="session_factory.statement_inspector">com.gpcoder.SqlCommentStatementInspector</property>

Lưu ý:

  • use_sql_comments : enable option này lên để cho phép Hibernate auto generate comment để minh hoạ cho ví dụ của chúng ta. Trong ứng dụng thực tế không cần enable option này cho StatementInspector cụ thể.

Một cách khác để đăng ký là thông qua SessionFactoryBuilder:


package com.gpcoder.utils;

import com.gpcoder.LoggingInterceptor;
import com.gpcoder.SqlCommentStatementInspector;
import org.hibernate.SessionFactory;
import org.hibernate.boot.Metadata;
import org.hibernate.boot.MetadataSources;
import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
import org.hibernate.service.ServiceRegistry;

public class HibernateUtils {

	private static final SessionFactory sessionFactory = buildSessionFactory();

	private HibernateUtils() {
		super();
	}

	private static SessionFactory buildSessionFactory() {
		ServiceRegistry serviceRegistry = new StandardServiceRegistryBuilder() //
				.configure() // Load hibernate.cfg.xml from resource folder by default
				.build();
		Metadata metadata = new MetadataSources(serviceRegistry).getMetadataBuilder().build();
		return metadata.getSessionFactoryBuilder()
                .applyStatementInspector( new SqlCommentStatementInspector() ) // Register StatementInspector
				.applyInterceptor( new LoggingInterceptor() ) // Register interceptor
				.build();
	}

	public static SessionFactory getSessionFactory() {
		return sessionFactory;
	}

	public static void close() {
		getSessionFactory().close();
	}
}

Tạo lớp ứng dụng


package com.gpcoder;

import com.gpcoder.entities.Tag;
import com.gpcoder.utils.HibernateUtils;
import lombok.extern.log4j.Log4j2;
import org.hibernate.Session;
import org.hibernate.SessionFactory;

@Log4j2
public class HibernateInterceptorExample {

    public static void main(String[] args) {
        try (SessionFactory sessionFactory = HibernateUtils.getSessionFactory();
             Session session = sessionFactory.openSession();
             ) {

            session.getTransaction().begin();

            Tag tag = new Tag();
            tag.setName("Hibernate Interceptor");
            session.persist(tag);

            session.getTransaction().commit();
        }
    }
}

Output:


2020-Apr-02 23:33:44 PM [main] DEBUG com.gpcoder.SqlCommentStatementInspector - Executing SQL query: select nextval ('tag_id_seq')
2020-Apr-02 23:33:44 PM [main] DEBUG com.gpcoder.SqlCommentStatementInspector - After removed: select nextval ('tag_id_seq')
2020-Apr-02 23:33:44 PM [main] DEBUG org.hibernate.SQL - select nextval ('tag_id_seq')
2020-Apr-02 23:33:44 PM [main] DEBUG com.gpcoder.LoggingInterceptor - onSave: Tag(id=50, name=Hibernate Interceptor)
2020-Apr-02 23:33:44 PM [main] DEBUG com.gpcoder.LoggingInterceptor - preFlush: Tag(id=50, name=Hibernate Interceptor)
2020-Apr-02 23:33:44 PM [main] DEBUG com.gpcoder.SqlCommentStatementInspector - Executing SQL query: /* insert com.gpcoder.entities.Tag */ insert into Tag (name, id) values (?, ?)
2020-Apr-02 23:33:44 PM [main] DEBUG com.gpcoder.SqlCommentStatementInspector - After removed: insert into Tag (name, id) values (?, ?)
2020-Apr-02 23:33:44 PM [main] DEBUG org.hibernate.SQL - insert into Tag (name, id) values (?, ?)
2020-Apr-02 23:33:44 PM [main] TRACE org.hibernate.type.descriptor.sql.BasicBinder - binding parameter [1] as [VARCHAR] - [Hibernate Interceptor]
2020-Apr-02 23:33:44 PM [main] TRACE org.hibernate.type.descriptor.sql.BasicBinder - binding parameter [2] as [BIGINT] - [50]
2020-Apr-02 23:33:44 PM [main] DEBUG com.gpcoder.LoggingInterceptor - postFlush: Tag(id=50, name=Hibernate Interceptor)

Như bạn thấy, comment của hibernate /* insert com.gpcoder.entities.Tag */ đã được loại bỏ một cách tự động nhờ vào StatementInspector.

Một số trường hợp khác có thể sử dụng StatementInspector: capture tất cả câu lệnh SQL được call bởi Hibernate, quản lý số lần SQL được gọi để phục vụ cho testing, reporting, …

Tài liệu tham khảo:

  • https://docs.jboss.org/hibernate/orm/5.4/userguide/html_single/Hibernate_User_Guide.html#events
  • https://vladmihalcea.com/hibernate-statementinspector/
4.9
09
Nếu bạn thấy hay thì hãy chia sẻ bài viết cho mọi người nhé! Và Donate tác giả

Shares

Chuyên mục: JPA Được gắn thẻ: Hibernate, Interceptor

Hibernate Batch processing
Giới thiệu JMS – Java Message Services

Có thể bạn muốn xem:

  • Hibernate Batch processing (06/04/2020)
  • Hibernate Cache (01/04/2020)
  • Giới thiệu về Hibernate (28/10/2019)
  • Tổng quan về JPA (Java Persistence API) (21/10/2019)
  • Sử dụng Hibernate Tools tạo các Entity và DAO class (29/01/2020)

Bình luận

bình luận

Tìm kiếm

Bài viết mới

  • Clean code 13/01/2024
  • Giới thiệu CloudAMQP – Một RabbitMQ server trên Cloud 02/10/2020
  • Kết nối RabbitMQ sử dụng Web STOMP Plugin 19/06/2020
  • Sử dụng publisher confirm trong RabbitMQ 16/06/2020
  • Sử dụng Dead Letter Exchange trong RabbitMQ 13/06/2020

Xem nhiều

  • Hướng dẫn Java Design Pattern – Factory Method (97662 lượt xem)
  • Hướng dẫn Java Design Pattern – Singleton (97348 lượt xem)
  • Giới thiệu Design Patterns (87188 lượt xem)
  • Lập trình đa luồng trong Java (Java Multi-threading) (85899 lượt xem)
  • Giới thiệu về Stream API trong Java 8 (83409 lượt xem)

Nội dung bài viết

  • 1 Hibernate Interceptor
  • 2 Hibernate StatementInspector

Lưu trữ

Thẻ đánh dấu

Annotation Authentication Basic Java Behavior Pattern Collection Creational Design Pattern Cấu trúc điều khiển Database Dependency Injection Design pattern Eclipse Exception Executor Service Google Guice Gson Hibernate How to Interceptor IO Jackson Java 8 Java Core JDBC JDK Jersey JMS JPA json JUnit JWT Message Queue Mockito Multithreading OOP PowerMockito RabbitMQ Reflection Report REST SOAP Structuaral Pattern Swagger Thread Pool Unit Test Webservice

Liên kết

  • Clean Code
  • JavaTpoint
  • Refactoring Guru
  • Source Making
  • TutorialsPoint
  • W3Schools Online Web Tutorials

Giới thiệu

GP Coder là trang web cá nhân, được thành lập với mục đích lưu trữ, chia sẽ kiến thức đã học và làm việc của tôi. Các bài viết trên trang này chủ yếu về ngôn ngữ Java và các công nghệ có liên quan đến Java như: Spring, JSF, Web Services, Unit Test, Hibernate, SQL, ...
Hi vọng góp được chút ít công sức cho sự phát triển cộng đồng Coder Việt.

Donate tác giả

Tìm kiếm các bài viết của GP Coder với Google Search

Liên hệ

Các bạn có thể liên hệ với tôi thông qua:
  • Trang liên hệ
  • Linkedin: gpcoder
  • Email: contact@gpcoder.com
  • Skype: ptgiang56it

Follow me

Copyright 2025 © GP Coder · All Rights Reserved · Giới thiệu · Chính sách · Điều khoản · Liên hệ ·

Share

Blogger
Delicious
Digg
Email
Facebook
Facebook messenger
Flipboard
Google
Hacker News
Line
LinkedIn
Mastodon
Mix
Odnoklassniki
PDF
Pinterest
Pocket
Print
Reddit
Renren
Short link
SMS
Skype
Telegram
Tumblr
Twitter
VKontakte
wechat
Weibo
WhatsApp
X
Xing
Yahoo! Mail

Copy short link

Copy link