Hibernate拦截器与事件监听
拦截器(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()
当完成一个事务之后,立刻调用此方法
1、使用拦截器实现操作日志
在应用系统中,对所有的数据库的操作都做记录,记录所操作内容,操作的用户和操作的时间
import org.hibernate.CallbackException; import org.hibernate.EmptyInterceptor; import org.hibernate.type.Type; import java.io.Serializable; import java.util.Date; public class DaoLogInterceptor extends EmptyInterceptor { private static final long serialVersionUID = 1L; @Override public void onDelete(Object entity, Serializable id, Object[] state, String[] propertyNames, Type[] types) { super.onDelete(entity, id, state, propertyNames, types); } @Override public boolean onSave(Object entity, Serializable id, Object[] state, String[] propertyNames, Type[] types) { return super.onSave(entity, id, state, propertyNames, types); } @Override public void onCollectionUpdate(Object collection, Serializable key) throws CallbackException { super.onCollectionUpdate(collection, key); } @Override public void onCollectionRemove(Object collection, Serializable key) throws CallbackException { super.onCollectionRemove(collection, key); } @Override public boolean onLoad(Object entity, Serializable id, Object[] state, String[] propertyNames, Type[] types) { return super.onLoad(entity, id, state, propertyNames, types); } @Override public boolean onFlushDirty(Object entity, Serializable id, Object[] currentState, Object[] previousState, String[] propertyNames, Type[] types) { System.out.println("operateTm:"+entity.getClass().getName()+"--OperateTm:"+new Date()+"--操作用户:当前登录用户"); getOperateDetails(previousState, currentState, propertyNames); return super.onFlushDirty(entity, id, currentState, previousState, propertyNames, types); } /** * 操作前后的数据差异 * * @param oldState * @param state * @param operateLog * @return */ private void getOperateDetails(Object[] oldState, Object[] state, String[] propertyNames) { for (int i = 0; i < propertyNames.length; i++) { if (!equalsObject(oldState[i], state[i])) { System.out.println("Field:"+propertyNames[i]+"NewValue:"+state[i] +"OldValue:"+oldState[i]); } } } private boolean equalsObject(Object o1, Object o2) { if (o1 == null && o2 != null) { return false; } if (o2 == null && o1 != null) { return false; } if (o1 == null && o2 == null) { return true; } return o1.equals(o2); } }
<!--hibernate配置--> <bean id="myInterceptor" class="com.sf.sfbuy2.context.filter.DaoLogInterceptor"/> <bean id="postUpdateListener" class="com.sf.sfbuy2.context.filter.PostUpdateListener"></bean> <bean id="sessionFactory" class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean"> <property name="dataSource"> <ref bean="dataSource"/> </property> <property name="entityInterceptor"> <ref bean="myInterceptor" /> </property> <property name="hibernateProperties"> <props> <prop key="hibernate.dialect">org.hibernate.dialect.Oracle10gDialect</prop> <prop key="hibernate.show_sql">true</prop> <prop key="hibernate.format_sql">true</prop> <prop key="use_sql_comments">true</prop> <prop key="javax.persistence.validation.mode">none</prop> <prop key="hibernate.validator.apply_to_ddl">false</prop> <prop key="hibernate.validator.autoregister_listeners">false</prop> </props> </property> <property name="packagesToScan"> <list> <value>com.sf.sfbuy2.db.entity</value> </list> </property> </bean>
2、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对象