Hibernate拦截器与监听器
来源:互联网 发布:linux 用户配额 编辑:程序博客网 时间:2024/05/25 20:00
监听器(Listener):其实功能与拦截器是相似的,但它实现原理不同,它是为每一个事件注册一个或多个监听器,一旦事件发生,则事件源通知所有监听该事件的监听器,然后监听器处理通知(观察者模式)。
-------------------------------------------------------------------------------------
拦截器
Hibernate为我们提供了实现拦截器的接口org.hibernate.Interceptor,它里面提供了许多拦截事件。通常不需要实现这个接口,因为我们实现自己的拦截器不可能每一个事件都是必须的。所以Hibernate为我们提供了org.hibernate.Interceptor接口的一个空实现类org.hibernate.EmptyIntercept,通常情况下我们只需继承这个空实现类,Override需要的事件方法即可。
拦截器的工作原理简易示意图:
设置拦截器后,相应的操作都会先穿过一层层相应的拦截器,让拦截器执行预处理或善后处理。
拦截器使用实例:
创建拦截器:
package customIntercept;import java.io.Serializable;import org.hibernate.EmptyInterceptor;import org.hibernate.type.Type;public class MyIntercept extends EmptyInterceptor {/** * */private static final long serialVersionUID = 5594120787569990595L;/* * entity - POJO对象 * id - POJO对象的主键 * state - POJO对象的每一个属性所组成的集合(除了ID) * propertyNames - POJO对象的每一个属性名字组成的集合(除了ID) * types - POJO对象的每一个属性类型所对应的Hibernate类型组成的集合(除了ID) */@Overridepublic boolean onSave(Object entity, Serializable id, Object[] state,String[] propertyNames, Type[] types) {System.out.println("-->onSave<--");for(int index=0; index<propertyNames.length; index++){if("sex".equals(propertyNames[index])){state[index] = "男";return true;}}return false;}}
测试方法:
@Testpublic void testCustomIntercept(){Session session = HibernateSessionFactory.getSessionFactory().openSession(new MyIntercept());User user = new User();user.setAge(20);user.setName("张三");Transaction tx = session.beginTransaction();session.save(user);tx.commit();}
测试方法中没有显式的设置User的性别,执行测试方法,查看数据库信息:
控制台打印:
可以发现保存的时候执行了过滤器,数据库表user的sex列也被赋值了,说明该赋值是拦截器完成的。
使用拦截器需要注意拦截器返回值,我以前一直以为拦截器的返回值会控制一个操作是否可以继续,通过实验发现,即使返回false操作也会继续执行的,只是返回false的话,拦截器的所有设置都是无效的,不会反应到数据库中。
返回false测试:
package customIntercept;import java.io.Serializable;import org.hibernate.EmptyInterceptor;import org.hibernate.type.Type;public class MyIntercept extends EmptyInterceptor {/** * */private static final long serialVersionUID = 5594120787569990595L;/* * entity - POJO对象 * id - POJO对象的主键 * state - POJO对象的每一个属性所组成的集合(除了ID) * propertyNames - POJO对象的每一个属性名字组成的集合(除了ID) * types - POJO对象的每一个属性类型所对应的Hibernate类型组成的集合(除了ID) */@Overridepublic boolean onSave(Object entity, Serializable id, Object[] state,String[] propertyNames, Type[] types) {System.out.println("-->onSave<--");for(int index=0; index<propertyNames.length; index++){if("sex".equals(propertyNames[index])){state[index] = "男";//return true;}}return false;}}
测试方法:
@Testpublic void testCustomInterceptfalse(){Session session = HibernateSessionFactory.getSessionFactory().openSession(new MyIntercept());User user = new User();user.setAge(21);user.setName("李四");Transaction tx = session.beginTransaction();session.save(user);tx.commit();}
查看数据库:
控制台打印:
可以发现数据依然保存到了数据库,但是拦截器的操作没有反映到数据库中,说明拦截器的操作时无效的。
控制台输出的sql语句与返回true的时候相比多了一条update语句,说明拦截器的操作会直接反映到数据库,但是如果拦截器返回的false,Hibernate会产生一条update语句将拦截器的操作回滚掉。
Hibernate拦截器可以分为两种:全局拦截器(SessionFactory范围内的)和局部拦截器(Session范围内的)
全局拦截器的设置方式:new Configuration().setInterceptor( new AuditInterceptor() );
局部拦截器的设置方式:Session session = sf.openSession( new AuditInterceptor() );
SessionFactory范围内的拦截器要通过Configuration中注册,而这必须在创建SessionFactory之前。在这种情况下,给出的拦截器会被这个SessionFactory所打开的所有session使用了;除非session打开时明确指明了使用的拦截器。SessionFactory范围内的拦截器,必须是线程安全的,因为多个session可能并发使用这个拦截器,要因此小心不要保存与session相关的状态。
------------------------------------------------------------------------------------
事件监听器
基本上,Session接口的每个方法都有相对应的事件。比如 LoadEvent,FlushEvent,等等(查阅XML配置文件的DTD,以及org.hibernate.event包来获得所有已定义的事件的列表)。当某个方法被调用时,Hibernate Session会生成一个相对应的事件并激活所有配置好的事件监听器。系统预设的监听器实现的处理过程就是被监听的方法要做的(被监听的方法所做的其实仅仅是激活监听器, “实际”的工作是由监听器完成的)。不过,你可以自由地选择实现一个自己定制的监听器(比如,实现并注册用来处理处理LoadEvent的LoadEventListener接口), 来负责处理所有的调用Session的load()方法的请求。
在定义自己的事件监听器时,其实不需要实现XXXListener接口,Hibernate为了方便我们定义事件监听器,已经为每个事件监听器接口实提供了一个默认的实现。在org.hibernate.event.def包下面可以找到Hibernate为我们提供的默认实现,我们只需要继承这些默认实现,在其基础上添加我们自定义的功能即可。
事件监听器的简单示意图:
当某个方法被调用时,Hibernate Session会生成一个相对应的事件并激活所有配置好的事件监听器。
事件监听器使用示例:
事件监听器代码:
package customListener;import org.hibernate.event.SaveOrUpdateEvent;import org.hibernate.event.def.DefaultSaveOrUpdateEventListener;import domain.User;public class MyListener extends DefaultSaveOrUpdateEventListener {/** * */private static final long serialVersionUID = 9057325840987859665L;@Overridepublic void onSaveOrUpdate(SaveOrUpdateEvent event) {System.out.println("-->执行onSaveOrUpdate<--");User user;if(event.getObject() instanceof User){user = (User) event.getObject();user.setSex("男");}/*一定要调用父类提供的功能,不然就和继承接口一样了*/super.onSaveOrUpdate(event);}}
如果监听器不执行父类的方法super.onSaveOrUpdate(event);则hibernate操作不会反应到数据库中。
通过hibernate.cfg.xml配置文件将事件监听器配置到Hibernate中:
第一种配置方式:
<?xml version='1.0' encoding='UTF-8'?><!DOCTYPE hibernate-configuration PUBLIC "-//Hibernate/Hibernate Configuration DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd"><hibernate-configuration> <session-factory> <property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property> <property name="hibernate.connection.url">jdbc:mysql://127.0.0.1:3306/hibernate3_6</property> <property name="hibernate.connection.username">root</property> <property name="hibernate.connection.password">root</property> <property name="hibernate.show_sql">true</property> <property name="hibernate.dialect">org.hibernate.dialect.MySQLDialect</property> <property name="hibernate.hbm2ddl.auto">update</property> <mapping resource="domain/user.hbm.xml" /> <event type="save-update"> <listener class="customListener.MyListener" /> </event> </session-factory></hibernate-configuration>
第二种配置方式:
<?xml version='1.0' encoding='UTF-8'?><!DOCTYPE hibernate-configuration PUBLIC "-//Hibernate/Hibernate Configuration DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd"><hibernate-configuration> <session-factory> <property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property> <property name="hibernate.connection.url">jdbc:mysql://127.0.0.1:3306/hibernate3_6</property> <property name="hibernate.connection.username">root</property> <property name="hibernate.connection.password">root</property> <property name="hibernate.show_sql">true</property> <property name="hibernate.dialect">org.hibernate.dialect.MySQLDialect</property> <property name="hibernate.hbm2ddl.auto">update</property> <mapping resource="domain/user.hbm.xml" /> <listener class="customListener.MyListener" type="save-update" /> </session-factory></hibernate-configuration>
注:监听器需要配置在mapping标签后面,不然会报错。
两种配置方式产生的效果都是一样的。只是一个以"事件"为主,一个以"监听器"为主。type是指定监听事件的类型,class指定监听器的实现类,一个事件可以有多个监听器。type有许多取值,下表列出了所有type的值:
上面列表每一个选项对应着一个特定的事件。
一个事件可以有多个事件监听器,如果自定义监听器里面没有执行父类的方法,而又想监听器操作反应到数据库中,那么可以在配置的时候加上默认监听器,例如:
<?xml version='1.0' encoding='UTF-8'?><!DOCTYPE hibernate-configuration PUBLIC "-//Hibernate/Hibernate Configuration DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd"><hibernate-configuration> <session-factory> <property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property> <property name="hibernate.connection.url">jdbc:mysql://127.0.0.1:3306/hibernate3_6</property> <property name="hibernate.connection.username">root</property> <property name="hibernate.connection.password">root</property> <property name="hibernate.show_sql">true</property> <property name="hibernate.dialect">org.hibernate.dialect.MySQLDialect</property> <property name="hibernate.hbm2ddl.auto">update</property> <mapping resource="domain/user.hbm.xml" /> <event type="save-update"> <listener class="customListener.MyListener" /> <listener class="org.hibernate.event.def.DefaultSaveOrUpdateEventListener" /> </event> </session-factory></hibernate-configuration>
测试方法代码:
@Testpublic void testCustomListener(){Session session = HibernateSessionFactory.getSession();System.out.println(session);User user = new User();user.setAge(50);user.setName("李四");Transaction tx = session.beginTransaction();session.saveOrUpdate(user);tx.commit();}
控制台打印:
可以发现在测试方法中,没有显示指定user的性别,但是在数据库中user表的sex列被赋值,说明监听器起作用了。
使用事件监听器需要注意父类行为的顺序,例如:
@Overridepublic void onSaveOrUpdate(SaveOrUpdateEvent event) {System.out.println("-->执行onSaveOrUpdate<--");User user;if(event.getObject() instanceof User){user = (User) event.getObject();user.setSex("男");}/*一定要调用父类提供的功能,不然就和继承接口一样了*/super.onSaveOrUpdate(event);}
@Overridepublic void onSaveOrUpdate(SaveOrUpdateEvent event) {super.onSaveOrUpdate(event);System.out.println("-->执行onSaveOrUpdate<--");User user;if(event.getObject() instanceof User){user = (User) event.getObject();user.setSex("男");}}
虽然两个监听器执行的结果是一样的,但是第二种情况会多产生一条update语句,就是先把值写入到数据库,然后hibernate在产生一条update语句对sex列进行赋值,而如果使用第一种方法,是先设置user的sex属性,然后在一次性的写入到数据库中。
通过编程方式将监听器注册到hibernate中:
监听器类不变,hibernate配置文件跟不配置监听器一样配置:
myhibernate.cfg.xml代码:
<?xml version='1.0' encoding='UTF-8'?><!DOCTYPE hibernate-configuration PUBLIC "-//Hibernate/Hibernate Configuration DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd"><hibernate-configuration> <session-factory> <property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property> <property name="hibernate.connection.url">jdbc:mysql://127.0.0.1/hibernate3_6</property> <property name="hibernate.connection.username">root</property> <property name="hibernate.connection.password">root</property> <property name="hibernate.show_sql">true</property> <property name="hibernate.dialect">org.hibernate.dialect.MySQLDialect</property> <property name="hibernate.hbm2ddl.auto">update</property> <property name="current_session_context_class">thread</property> <mapping resource="domain/user.hbm.xml" /> </session-factory></hibernate-configuration>
测试方法代码:
@Testpublic void testCustomListener2(){SaveOrUpdateEventListener[] event = {new MyListener()};Configuration cfg = new Configuration().configure("/myhibernate.cfg.xml");cfg.getEventListeners().setSaveOrUpdateEventListeners(event);Session session = cfg.buildSessionFactory().getCurrentSession();System.out.println(session);User user = new User();user.setAge(50);user.setName("李四");Transaction tx = session.beginTransaction();session.saveOrUpdate(user);tx.commit();}执行结果跟使用xml配置的结果一样。
通过在XML配置文件声明而注册的监听器不能共享实例。如果在多个<listener/>节点中使用 了相同的类的名字,则每一个引用都将会产生一个独立的实例。如果你需要在多个监听器类型之间共享 监听器的实例,则你必须使用编程的方式来进行注册。
- Hibernate拦截器与监听器
- Hibernate拦截器和监听器
- Hibernate拦截器和监听器
- Hibernate拦截器和监听器
- Hibernate拦截器(Interceptor)与事件监听器(Listener)
- Hibernate拦截器(Interceptor)与事件监听器(Listener)
- Hibernate拦截器(Interceptor)与事件监听器(Listener)
- Hibernate拦截器(Interceptor)与事件监听器(Listener)
- Hibernate拦截器(Interceptor)与事件监听器(Listener)
- Hibernate拦截器(Interceptor)与事件监听器(Listener)
- Hibernate拦截器(Interceptor)与事件监听器(Listener)
- Hibernate的拦截器和监听器
- Hibernate的拦截器和监听器
- Hibernate的拦截器和监听器 .
- Servlet监听器、过滤器与Spring拦截器
- 过滤器、监听器与拦截器区别
- springboot的监听器,拦截器与过滤器
- Hibernate Spring 拦截器和监听器的使用
- CC2530遇到的低功耗问题
- 问题一百四十九:人见人爱的A-B
- android的PowerManager和PowerManager.WakeLock
- [MSSQL]获取数据库的一些基本信息
- ARM-GCC-LD脚本
- Hibernate拦截器与监听器
- Android SQLite 详解
- ubuntu 安装福昕阅读器(wine方式)
- 从程序员到项目经理(6):程序员加油站 -- 懂电脑更要懂人脑
- Ural 1172 Ship Routes
- 反射 类的方法
- ShareSDK的简化压缩和使用例子
- GridView使用示例(二)
- paging流程