一次偶然的机会发现了他们的差别
最近正在学习hibernate,学习资料里用的是hibernate3作为背景,而我从SourceForge上下载了最新hibernate-release-4.3.8.Final.zip。前面的练习一切正常:包括基本的全局配置,实体配置,实体间关联关系的定义以及锁机制等等。最后在处理监听器(EventListener)的时候发现不论在hibernate.cfg.xml里怎么定义拦截器都不起作用。后来新下载了一个hibernate-3.2.5.ga.zip,重新运行,一切如常。在网上也查了很多资料来解决hibernate4里监听器的问题,发现写得都比较含糊,有些地方是和Spring以及Structs一起的解决办法,都没有实际解决我的问题。后来在stackoverflow上看到一个介绍(网址在最后),研读之后,对我自己的代码基于hibernate4做了相应的修改,可以正常工作了。
前面说了这么多废话,现在进入正题吧。
之前已经定义好了一个Student的class。要做的事情很简单,就是在新增一条记录的时候让自己定义的EventListner在Sname后加上随机数。
hibernate.cfg.xml中的mapping关系定义如下:
<mapping resource="domain/Student.hbm.xml" />
Student.java定义如下:(get/set方法已省略)
public class Student {
private int Sid;
private String Sname, Sage, Ssex;
private int version;
}
自定义的EventListner类SaveStudentListner.java如下:
public class SaveStudentListener implements SaveOrUpdateEventListener {
/**
*
*/
private static final long serialVersionUID = 1L;
@Override
public void onSaveOrUpdate(SaveOrUpdateEvent arg0)
throws HibernateException {
// TODO Auto-generated method stub
System.out.println("Catch save event.");
if (arg0.getObject() instanceof domain.Student){
Student st = (Student)arg0.getObject();
System.out.println("Handle save student: " + st.getSname());
int i = (int) (100*Math.random());
System.out.println("Random number is: " + i);
st.setSname(st.getSname() + i);
}
}
}
额外定义了一个处理hibernate 的session的util类:
public class HibernateUtil {
private static SessionFactory sf;
private HibernateUtil() {
}
static {
Configuration cf = new Configuration();
cf.configure();
sf = cf.buildSessionFactory();
}
public static SessionFactory getSessionFactory() {
return sf;
}
public static Session getSession() {
return sf.openSession();
}
}
hibernate3中如何实现事件监听
在hibernate.cfg.xml中新加一个section:
<!-- Only available for Hibernate 3.0 -->
<event type="save">
<listener class="domain.SaveStudentListener" />
<listener class="org.hibernate.event.def.DefaultSaveOrUpdateEventListener"/>
</event>
测试类定义如下:
public static void main(String[] args) {
add();
}
static void add() {
Session s = null;
Transaction tx = null;
try {
s = HibernateUtil.getSession();
tx = s.beginTransaction();
Student st = new Student();
st.setSname("Event3.0");
s.save(st);
tx.commit();
}catch(Exception e){
System.out.println("Error occur during add Student: " + e.getMessage());
}
finally {
if (s != null)
s.close();
}
}
运行test类,得到如下结果:
Hibernate: insert into Student (version, Sname, Sage, Ssex) values (?, ?, ?, ?)
Catch save event.
Handle save student: Event4.0
Random number is: 1
Hibernate: update Student set version=?, Sname=?, Sage=?, Ssex=? where Sid=? and version=?
如果只定义了<listener class="domain.SaveStudentListener" />,会导致最后没有数据库插入的sql,必须加上<listener class="org.hibernate.event.def.DefaultSaveOrUpdateEventListener"/>
hibernate4中如何实现事件监听
现在把所有hibernate3相关的jar包替换为hibernate4的jar包 (hibernate-release-4.3.8.Final\lib\required下所有的jar包),重新运行一次test类。
得到结果如下:
Hibernate: insert into Student (version, Sname, Sage, Ssex) values (?, ?, ?, ?)
为什么没有进入到eventlistener呢?
因为hibernate4中的eventlistener机制发生了翻天覆地的变化,hibernate4不再从hibernate.cfg.xml中读取event listener相关信息。
那怎么办?
hibernate4提供了全新的办法,我们把test类稍做修改(高亮部分):
注意高亮部分:要传递自定义的event listener的class名:SaveStudentListener.class
public static void main(String[] args) {
//For Hibernate 4.0
//http://in.relation.to/Bloggers/EventListenerRegistration
//org.hibernate.integrator.spi.Integrator
<span style="white-space:pre"> </span>final EventListenerRegistry eventListenerRegistry = ((SessionFactoryImpl) HibernateUtil.getSessionFactory()).getServiceRegistry().getService( EventListenerRegistry.class );
eventListenerRegistry.appendListeners( EventType.SAVE, SaveStudentListener.class );
add();
//update(2);
}
static void add() {
Session s = null;
Transaction tx = null;
try {
s = HibernateUtil.getSession();
//s = new Configuration().configure().buildSessionFactory().openSession();
tx = s.beginTransaction();
Student st = new Student();
st.setSname("Event4.0");
s.save(st);
// 交换以上两句的位置,看Hibernate执行的sql语句。会再增加一条更新操作。
tx.commit();
}catch(Exception e){
System.out.println("Error occur during add Student: " + e.getMessage());
}
finally {
if (s != null)
s.close();
}
}
运行结果如下:
Hibernate: insert into Student (version, Sname, Sage, Ssex) values (?, ?, ?, ?)
Catch save event.
Handle save student: Event4.0
Random number is: 70
Hibernate: update Student set version=?, Sname=?, Sage=?, Ssex=? where Sid=? and version=?
个人觉得新的方法其实要简单一些,不用担心覆盖掉原有的eventlistener。
hibernate4提供了三种添加event listener的方法,正如http://in.relation.to/Bloggers/EventListenerRegistration中所说:
// EventListenerRegistry defines 3 ways to register listeners: // 1) This form overrides any existing registrations with eventListenerRegistry.setListeners( EventType.AUTO_FLUSH, myCompleteSetOfListeners ); // 2) This form adds the specified listener(s) to the beginning of the listener chain eventListenerRegistry.prependListeners( EventType.AUTO_FLUSH, myListenersToBeCalledFirst ); // 3) This form adds the specified listener(s) to the end of the listener chain eventListenerRegistry.appendListeners( EventType.AUTO_FLUSH, myListenersToBeCalledLast );