攔截器(Interceptor)
org.hibernate.Interceptor接口定義了Hibernate中通用攔截機制
創建Session對象的時候,所有的Session對象或者這個Session對象的所有持久化操作的動作都會被指定的攔截器進行攔截.
Interceptor接口的方法
- afterTransactionBegin()
當一個事務時候啟動時,會立刻調用這個方法,這個方法可以改變這個事務的狀態,例如:回滾事務 - instantiate()
創建對象,如果返回null,則Hibernate將調用實體類的默認構造方法創建持久化對象 - getEntity()
當一個持久化對象,通過標示符屬性在Session對象的緩存中進行查找,並且沒有找到時,會調用該方法 - getEntityName()
當session對象獲取持久化對象的名字時,會調用這個方法 - onLoad()
該方法在持久化對象初始化之前加載,這個的持久化對象處於剛被創建的狀態(對象的屬性值都未賦值) - findDirty()
當調用Session對象的flush()方法時,講調用該方法判斷對象是否為臟數據,這是臟數據檢查的另外攔截的實現方式 - isTransient()
當調用Session對象的saveOrUpdate方法時,會調用該方法判斷對象是否尚未保存 - onSave()
在對象被保存之前調用,通過這個方法可以對要保持的對象的屬性進行修改 - onDelete()
該方法在持久化對象被刪除之前調用 - preFlush()
該方法當調用Session對象的flush()方法之前被調用 - onFlushDirty()
當調用Session對象flush()方法進行臟數據檢查時,如果發現持久化對象的狀態發生了改變,會調用該方法 - postFlush()
該方法調用Session對象的flush()方法之后被調用 - beforeTransactionCompletion()
在完成一個事務之前,調用此方法,這個方法可以改變事務的狀態,例如回滾事務 - afterTransactionCompletion()
當完成一個事務之后,立刻調用此方法
使用攔截器實現審計日志
審計日志指的是,在應用系統中,對所有的數據庫的操作都做記錄,記錄所操作內容,操作的用戶和操作的時間
demo
log4j.properties
- log4j.logger.com.rbh.examples=info,appender1
- log4j.appender.appender1=org.apache.log4j.FileAppender
- log4j.appender.appender1.layout=org.apache.log4j.TTCCLayout
- log4j.appender.appender1.File=ligfile.txt
LogEntityInterceptor
- package com.rbh.examples;
- import java.io.Serializable;
- import org.apache.log4j.Logger;
- import org.hibernate.EmptyInterceptor;
- import org.hibernate.type.Type;
- public class LogEntityInterceptor extends EmptyInterceptor {
- private static final long serialVersionUID = 1L;
- private Logger logger = Logger.getLogger(LogEntityInterceptor.class);
- public void onDelete(Object entity,Serializable id, Object[] state,String[] propertyNames,
- Type[] types){
- logger.info("刪除數據");
- }
- public boolean onFlushDirty(Object entity,Serializable id, Object[] currentState,
- Object[] preState,String[] propertyNames,
- Type[] types){
- logger.info("修改數據");
- return false;
- }
- public boolean onSave(Object entity,Serializable id, Object[] State,
- String[] propertyNames,
- Type[] types){
- logger.info("保存數據");
- return false;
- }
- }
HibernateTest
- package com.rbh.examples;
- import java.util.Date;
- import org.hibernate.Session;
- import org.hibernate.SessionFactory;
- import org.hibernate.cfg.Configuration;
- public class HibernateTest {
- public static void main(String[] args)
- {
- HibernateTest test =new HibernateTest();
- test.testInterceptor();
- }
- public void testInterceptor()
- {
- LogEntityInterceptor interceptor=new LogEntityInterceptor();
- Configuration config=new Configuration();
- config.setInterceptor(interceptor);
- config.configure();
- SessionFactory sf=config.buildSessionFactory();
- Session session=sf.getCurrentSession();
- Guestbook gb= new Guestbook();
- gb.setName("Narcissus");
- gb.setEmail("javac.q@gmail.com");
- gb.setCreatedTime(new Date());
- gb.setPhone("11102121");
- gb.setTitle("test Interceptor");
- gb.setContent("test Interceptor,test Interceptor");
- session.beginTransaction();
- session.save(gb);
- session.getTransaction().commit();
- session=sf.getCurrentSession();
- gb.setName("tom");
- session.beginTransaction();
- session.update(gb);
- session.getTransaction().commit();
- session=sf.getCurrentSession();
- session.beginTransaction();
- session.delete(gb);
- session.getTransaction().commit();
- }
- }
可以通過session方式加載攔截器對象,也可以通過Configuration對象加載攔截器
Configuration:對所有的session都會被攔截
session:只對當前的session進行攔截
Hibernate的事件監聽機制
Hibernate中的事件監聽機制可以對Session對象的動作進行監聽,一旦發生了特殊的事件,Hibernate就會執行監聽器中的事件處理方法
在某些功能的設計中,我們即可以使用Hibernate的攔截器實現,也可以使用Hibernate的事件監聽來實現
Hibernate中事件與對應的監聽器接口
事件類型 監聽器接口
auto-flush AutoFlushEventListener
merge MergeEventListener
delete DeleteEventListener
persist PersistEventListener
dirty-check DirtyCheckEventListener
evice EvictEventListener
flush FlushEventListener
flush-entity FlushEntityEventListener
load LoadEventListener
load-collection InitializeCollectEventListener
lock LockEventListener
refresh RefreshEventListener
replicate ReplicateEventListener
save-update SaveOrUpdateEventListener
pre-load PreLoadEventListener
pre-update PreUpdateEventListener
pre-delete PreDeleteEventListener
pre-insert PreInsertEventListener
post-load PostLoadEventListener
post-update PostUpdateEventListener
post-delete PostDeleteEventListener
post-insert PostInsertEventListener
應用Hibernate事件監聽器
用戶制定的事件監聽器首先需要實現與所需要處理的事件對應的接口,或者繼承實現這個接口的類
通過使用Hibernate的配置文件(hibernate.cfg.xml)配置事件監聽對象,或者使用Configuration對象注冊這個定制的事件監聽器對象
LogPostLoadEventListener
- import org.hibernate.event.PostLoadEvent;
- import org.hibernate.event.PostLoadEventListener;
- public class LogPostLoadEventListener implements PostLoadEventListener {
- private static final long serialVersionUID = 404241098418965422L;
- public void onPostLoad(PostLoadEvent event) {
- System.out.println("Class:" + event.getEntity().getClass().getName() + ",id:"
- + event.getId());
- }
- }
修改Hibernate.cfg.xml文件
- <mapping resource="com/rbh/examples/Guestbook.hbm.xml" />
- <listener type="post-load" class="com.rbh.examples.LogPostLoadEventListener" />
- </session-factory>
- </hibernate-configuration>
或者通過Configuration 對象注冊這個監聽器對象
- Configuration config = new Configuration();
- config.setListener("post-load", new LogPostLoadEventListener());
- config.configure();
- Session session = config.buildSessionFactory().getCurrentSession();
編寫、配置好監聽器以后,當通過Session對象的load()、get()方法或者Query對象的list方法加載持久化對象之后,LogPostEventListener對象中的onPostLoad()方法就會被執行.
使用監聽器實現審計日志
利用Hibernate的事件機制,不僅能夠精確追蹤到持久化對象的字段的修改,持久化對象關聯關系的變更,還能記錄更新前的數值和更新后的數值
監聽器與攔截器的比較
監聽器可以實現更細化粒度的攔截
通過監聽器獲取所攔截的持久化對象的修改后喝修改前的狀態值
能直接通過Event對象獲取Session對象
使用監聽器實現審計日志的一個demo 見附件
簡要說明:AuditLog表式記錄 日志的表
AuditLog.java 和AuditLog.hbm.xml表的持久化映射
AuditLogEventListener 具體的實現類