微信网站 手机网站,建站行业,沈阳网站建设企业,表格布局网站4.8 事 件 机 制 通常#xff0c;Hibernate执行持久化过程中#xff0c;应用程序无法参与其中。所有的数据持久化操作#xff0c;对用户都是透明的#xff0c;用户无法插入自己的动作。 通过事件框架#xff0c;Hibernate允许应用程序能响应特定的内部事件#xff0c;从而…4.8 事 件 机 制 通常Hibernate执行持久化过程中应用程序无法参与其中。所有的数据持久化操作对用户都是透明的用户无法插入自己的动作。 通过事件框架Hibernate允许应用程序能响应特定的内部事件从而允许实现某些通用的功能或对Hibernate功能进行扩展。 Hibernate的事件框架由两个部分组成 ● 拦截器机制对于特定动作拦截回调应用中的特定动作。 ● 事件系统重写Hibernate的事件监听器。 4.8.1 拦截器 通过Interceptor接口可以从Session中回调应用程序的特定方法这种回调机制可让应用程序在持久化对象被保存、更新、删除或加载之前检查并修改其属性。 通过Interceptor接口可以在数据进入数据库之间对数据进行最后的检查如果数据不符合要求可以修改数据从而避免非法数据进入数据库。当然通常无须这样做只是在某些特殊的场合下才考虑使用拦截器完成检查功能。 使用拦截器可按如下步骤进行 1定义实现Interceptor接口的拦截器类 2通过Session启用拦截器或者通过Configuration启用全局拦截器。 下面是一个拦截器的示例代码该拦截器没有进行任何实际的操作仅仅打印出标志代码 public class MyInterceptor extends EmptyInterceptor { //更新的次数 private int updates; //插入的次数 private int creates; //删除数据时将调用onDelete方法 public void onDelete(Object entity,Serializable id,Object[] state,String[] propertyNames, Type[] types) { //do nothing } //同步Session和数据库中的数据 public boolean onFlushDirty(Object entity, Serializable id, Object[] currentState, Object[] previousState, String[] propertyNames, Type[] types) { //每同步一次修改的累加器加1 updates; for ( int i0; i propertyNames.length; i ) { if ( lastUpdateTimestamp.equals( propertyNames[i] ) ) { currentState[i] new Date(); return true; } } return false; } //加载持久化实例时调用该方法 public boolean onLoad(Object entity,Serializable id,Object[] state,String[] propertyNames,Type[] types) { System.out.println(); for ( int i0; i propertyNames.length; i ) { if ( name.equals( propertyNames[i] ) ) { System.out.println(state[i]); state[i] aaa; return true; } } return false; } //保存持久化实例时调用该方法 public boolean onSave(Object entity,Serializable id,Object[] state,String[] propertyNames,Type[] types) { creates; for ( int i0; ipropertyNames.length; i ) { if ( createTimestamp.equals( propertyNames[i] ) ) { state[i] new Date(); return true; } } return false; } //提交刷新 public void postFlush(Iterator entities) { System.out.println(创建的次数 creates , 更新的次数 updates); } public void preFlush(Iterator entities) { updates0; creates0; } //事务提交前触发该方法 public void beforeTransactionCompletion(Transaction tx) { System.out.println(事务即将结束); } //事务提交后触发该方法 public void afterTransactionCompletion(Transaction tx) { System.out.println(事务已经结束); } } 在上面的拦截器实现类中实现了很多方法这些方法都是在Hibernate执行特定动作时自动调用。 完成了拦截器的定义下面是关于拦截器的使用。拦截器的使用有两种方法 ● 通过SessionFactory的openSessionInterceptor in方法打开一个带局部拦截器的Session。 ● 通过Configuration的setInterceptorInterceptor in方法设置全局拦截器。 下面是使用局部拦截器的示例代码 public class HibernateUtil { //静态类属性 SessionFactory public static final SessionFactory sessionFactory; //静态初始化块完成静态属性的初始化 static { try { //采用默认的hibernate.cfg.xml来启动一个Configuration的实例 Configuration configurationnew Configuration().configure(); //由Configuration的实例来创建一个SessionFactory实例 sessionFactory configuration.buildSessionFactory(); } catch (Throwable ex) { System.err.println(初始化sessionFactory失败. ex); throw new ExceptionInInitializerError(ex); } } //ThreadLocal是隔离多个线程的数据共享不存在多个线程之间共享资源因此不再需要 对线程同步 public static final ThreadLocal session new ThreadLocal(); //不加拦截器的打开Session方法 public static Session currentSession() throws HibernateException { Session s (Session) session.get(); //如果该线程还没有Session则创建一个新的Session if (s null) { s sessionFactory.openSession(); //将获得的Session变量存储在ThreadLocal变量的Session里 session.set(s); } return s; } //加拦截器的打开Session方法 public static Session currentSession(Interceptor it) throws HibernateException { Session s (Session) session.get(); //如果该线程还没有Session则创建一个新的Session if (s null) { //以拦截器创建Session对象 s sessionFactory.openSession(it); //将获得的Session变量存储在ThreadLocal变量的Session里 session.set(s); } return s; } //关闭Session对象 public static void closeSession() throws HibernateException { Session s (Session) session.get(); if (s ! null) s.close(); session.set(null); } } 上面的Hibernate工具类提供了两个currentSession方法分别用于不使用拦截器获取Session对象和使用拦截器获取Session对象。 下面是主程序使用拦截器的代码片段 private void testUser() { //以拦截器开始Session Session session HibernateUtil.currentSession(new MyInterceptor()); //开始事务 Transaction tx session.beginTransaction(); //执行下面的代码时可以看到系统回调onSave等方法 /* User u new User(); u.setName(Yeeku Lee); u.setAge(28); u.setNationality(中国); session.persist(u); u.setAge(29); u.setAge(30); session.persist(u); */ //执行下面的代码时可以看到系统回调onLoad等方法 Object o session.load(User.class , new Integer(1)); System.out.println(o); User u (User)o; System.out.println(u.getName()); //提交事务时可以看到系统回调事务相关方法 tx.commit(); HibernateUtil.closeSession(); } 4.8.2 事件系统 Hibernate 3的事件系统是功能更强大的事件框架事件系统可以替代拦截器也可以作为拦截器的补充来使用。 基本上Session接口的每个方法都有对应的事件。如LoadEvent和FlushEvent等。当Session调用某个方法时Hibernate Session会生成对应的事件并激活对应的事件监听器。 系统默认监听器实现的处理过程完成了所有的数据持久化操作包括插入和修改等操作。如果用户定义了自己的监听器则意味着用户必须完成对象的持久化操作。 例如可以在系统中实现并注册LoadEventListener监听器该监听器负责处理所有调用Session的load()方法的请求。 监听器是单态模式对象即所有同类型的事件处理共享同一个监听器实例因此监听器不应该保存任何状态即不应该使用成员变量。 使用事件系统可按如下步骤进行 1实现自己的事件监听器类 2注册自定义事件监听器代替系统默认的事件监听器。 实现用户的自定义监听器有如下3个方法 ● 实现对应的监听器接口这是不可思议的实现接口必须实现接口内的所有方法关键是必须实现Hibernate对应的持久化操作即数据库访问这意味着程序员完全取代了Hibernate的底层操作。 ● 继承事件适配器可以选择性地实现需要关注的方法但依然试图取代Hibernate完成数据库的访问这也不太现实。 ● 继承系统默认的事件监听器扩展特定方法。 实际上前两种方法很少使用。因为Hibernate的持久化操作也是通过这些监听器实现的如果用户取代了这些监听器则应该自己实现所有的持久化操作这意味着用户放弃了Hibernate的持久化操作而改为自己完成Hibernate的核心操作。 通常推荐采用第三种方法实现自己的事件监听器。Hibernate默认的事件监听器都被声明成non-final从而方便用户继承。 下面是用户自定义监听器的示例 //自定义LoadListener继承默认的DefaultLoadEventListener实现类 public class MyLoadListener extends DefaultLoadEventListener { //在LoadEventListener接口仅仅定义了这个方法 public Object onLoad(LoadEvent event, LoadEventListener.LoadType loadType)throws HibernateException { //先调用父类的onLoad方法从而完成默认的持久化操作 Object o super.onLoad(event, loadType); //加入用户的自定义处理 System.out.println(自定义的load事件); System.out.println(event.getEntityClassName() event.getEntityId()); return o; } } 下面还有一个MySaveListener用于监听SaveEvent事件 //自定义SavaListener继承默认的DefaultSaveEventListener实现类 public class MySaveListener extends DefaultSaveEventListener { //该方法完成实际的数据插入动作 protected Serializable performSaveOrUpdate(SaveOrUpdateEvent event) { //先执行用户自定义的操作 System.out.println(event.getObject()); //调用父类的默认持久化操作 return super.performSaveOrUpdate(event); } } 注意扩展用户自定义监听器时别忘了在方法中调用父类的对应方法。 注册用户自定义监听器也有两种方法 ● 编程式通过使用Configuration对象编程注册。 ● 声明式在Hibernate的XML格式配置文件中进行声明使用Properties格式的配置文件将无法配置自定义监听器。 下面的示例代码通过编程方式使用自定义监听器 public class HibernateUtil2 { //静态类属性 SessionFactory public static final SessionFactory sessionFactory; //静态初始化块完成静态属性的初始化 static { try { Configuration cfg new Configuration(); //注册loadEventListener监听器 cfg.getSessionEventListenerConfig().setLoadEventListener ( new MyLoadListener() ); //注册saveListener监听器 cfg.getSessionEventListenerConfig().setSaveEventListener (new MySaveListener() ); //由Configuration实例来创建一个SessionFactory实例 sessionFactory cfg.configure().buildSessionFactory(); } catch (Throwable ex) { System.err.println(初始化sessionFactory失败. ex); throw new ExceptionInInitializerError(ex); } } //ThreadLocal是隔离多个线程的数据共享不存在多个线程之间共享资源因此不再需要 对线程同步 public static final ThreadLocal session new ThreadLocal(); //不加拦截器的打开Session方法 public static Session currentSession() throws HibernateException { Session s (Session) session.get(); //如果该线程还没有Session则创建一个新的Session if (s null) { s sessionFactory.openSession(); //将获得的Session变量存储在ThreadLocal变量的Session里 session.set(s); } return s; } //关闭Session对象 public static void closeSession() throws HibernateException { Session s (Session) session.get(); if (s ! null) s.close(); session.set(null); } } 如果不想修改代码也可以在配置文件中使用事件监听器注册事件监听器的Hibernate配置文件代码如下 ?xml version1.0 encodingGBK? !-- Hibernate配置文件的文件头包含DTD等信息 -- !DOCTYPE hibernate-configuration PUBLIC -//Hibernate/Hibernate Configuration DTD 3.0//EN http://hibernate.sourceforge.net/hibernate-configuration-3.0. dtd !-- Hibernate配置文件的根元素 -- hibernate-configuration session-factory !—设置数据库驱动 -- property nameconnection.driver_classcom.mysql.jdbc.Driver /property !-- 数据库服务的url -- property nameconnection.urljdbc:mysql://localhost/hibernate /property !-- 数据库服务的用户名 -- property nameconnection.usernameroot/property !-- 数据库服务的密码 -- property nameconnection.password32147/property !-- JDBC connection pool (use the built-in) -- property nameconnection.pool_size5/property !-- 设置数据库方言 -- property namedialectorg.hibernate.dialect.MySQLDialect /property !-- 显示Hibernate生成的SQL语句 -- property nameshow_sqltrue/property !-- 配置应用启动时是否启动自动建表 -- property namehbm2ddl.autoupdate/property !-- 列出所有的持久化映射文件 -- mapping resourceUser.hbm.xml/ !-- 注册事件监听器 -- listener typeload classlee.MyLoadListener/ listener typesave classlee.MySaveListener/ /session-factory /hibernate-configuration 使用配置文件注册事件监听器虽然方便但也有不利之处通过配置文件注册的监听器不能共享实例。如果多个listener/元素中使用了相同的类则每一个引用都将产生一个新的拦截器实例。如果需要在多个事件之间共享监听器的实例则必须使用编程方式注册事件监听器。 注意虽然监听器类实现了特定监听器的接口在注册的时候还要明确指出注册的事件。这是因为一个类可能实现多个监听器的接口注册时明确指定要监听的事件可以使得启用或者禁用某个事件监听的配置工作更简单。 转载于:https://www.cnblogs.com/jadmin/archive/2009/07/19/2206094.html