论坛首页 Java企业应用论坛

介绍Hibernate中的Interceptor

浏览 27437 次
该帖已经被评为精华帖
作者 正文
   发表时间:2004-11-03  
对于Audit这个功能而言, 偶只用实现onFlushDirty和onSave, 其他的倒用不到:

public abstract class AbstractAuditInterceptor implements Interceptor, Serializable {

    public boolean onFlushDirty(Object entity, Serializable id, Object[] currentState, Object[] previousState, String[] propertyNames, Type[] types);
            throws CallbackException {
        if (entity instanceof Auditable); {
            AuditInfo ai = ((Auditable); entity);.getAuditInfo();;
            if (ai == null); {
                ai = new AuditInfo();;
                ((Auditable); entity);.setAuditInfo(ai);;
            }
            ai.setLastUpdated(new Date(););;
            ai.setUpdatedBy(getUserId(););;
        }
        return false;
    }

    public boolean onSave(Object entity, Serializable id, Object[] state, String[] propertyNames, Type[] types); throws CallbackException {
        if (entity instanceof Auditable); {
            AuditInfo ai = ((Auditable); entity);.getAuditInfo();;
            if (ai == null); {
                ai = new AuditInfo();;
                ((Auditable); entity);.setAuditInfo(ai);;
            }            
            ai.setCreated(new Date(););;
            ai.setCreatedBy(getUserId(););;
        }
        return false;
    }

    public abstract String getUserId();;
}


用AOP做这种事情? 哼哼, 偶不爽......
0 请登录后投票
   发表时间:2005-01-27  
public boolean onFlushDirty(Object entity, Serializable id,
                                Object[] newValues, Object[] oldValues, String[] properties, Type[] types);
            throws CallbackException
    {
        System.out.println(Arrays.asList(properties););;
        System.out.println(Arrays.asList(oldValues););; // is null
        System.out.println(Arrays.asList(newValues););;
        System.out.println(oldValues);;
        System.out.println(newValues);;
        return false;
}


为何oldValues返回null,properties和newValues都正常!
0 请登录后投票
   发表时间:2005-01-27  
water 写道
为何oldValues返回null,properties和newValues都正常!

版本?代码?配置?偶都看不到......
0 请登录后投票
   发表时间:2005-01-27  
<bean id="sessionFactory" class="org.springframework.orm.hibernate.LocalSessionFactoryBean">
        <property name="dataSource">
            <ref local="dataSource"/>
        </property>
        <property name="mappingDirectoryLocations">
            <list>
                <value>com/test/pojo</value>
            </list>
        </property>
        <property name="hibernateProperties">
            <props>
                <prop key="hibernate.dialect">net.sf.hibernate.dialect.Oracle9Dialect</prop>
            </props>
        </property>
        <property name="entityInterceptor">
            <ref local="historyInterceptor"/>
        </property>
</bean>

<bean id="historyInterceptor"
        class="com.test.interceptor.HistoryInterceptor">
</bean>


public class HistoryInterceptor implements Interceptor
{

   // other method

public boolean onFlushDirty(Object entity, Serializable id,
                                Object[] newValues, Object[] oldValues, String[] properties, Type[] types);
            throws CallbackException
    {
        System.out.println(Arrays.asList(properties););; // ok
        System.out.println(entity.getClass();.getName(););; // ok
        System.out.println(oldValues);;  // null
        System.out.println(newValues);; // ok 
        

        return false;
    }
}

test code;

public void testUpdateGoods(); throws Exception
    {
        Goods goods = this.goodsDAO.getGoods(new Integer(12225););;
        String oldName = goods.getName();;
        goods.setName(oldName + "1");;
        this.goodsDAO.updateGoods(goods);;
        goods = this.goodsDAO.getGoods(new Integer(12225););;
        assertEquals(oldName + "1", goods.getName(););;
    }
0 请登录后投票
   发表时间:2005-01-27  
Session session = sessionFactory.openSession(new HistoryInterceptor(););;
        Transaction tx = session.beginTransaction();;
        Goods goods = (Goods); session.load(Goods.class, new Integer(12225););;
        String oldName = goods.getName();;
        goods.setName(oldName + "1");;
        session.update(goods);;
        session.flush();;
        tx.commit();;
        goods = (Goods); session.load(Goods.class, new Integer(12225););;
        session.close();;
        sessionFactory.close();;
        assertEquals(oldName + "1", goods.getName(););;

这样就OK了!

Spring的LocalSessionFactoryBean是这样实现的
if (this.entityInterceptor != null); {
			// set given entity interceptor at SessionFactory level
			config.setInterceptor(this.entityInterceptor);;
		}


请问
Session session = sessionFactory.openSession(new HistoryInterceptor(););;


configuration.setInterceptor(this.entityInterceptor);;

有什么不同?
0 请登录后投票
   发表时间:2007-01-31  
引用
写自己的Interceptor目前有一个问题就是它需要实现的方法太多, 有一些还能通过名字直接看出来意义, 比如onSave, onLoad, 有一些就得看javadoc, 甚至查看hibernate的源代码了. 所以Hibernate 3把Interceptor咔嚓掉, 用更丰富的Event/EventListener来达到同样的可扩展性目的.
hibernate3里不是可以继承EmptyInterceptor这个类吗?可以根据需要来重写啊。
0 请登录后投票
   发表时间:2007-01-31  
详细的请看这里http://blog.sina.com.cn/u/49bc2ffd010007gd
hibernate.cfg.xml的内容如下:
<?xml version='1.0' encoding='utf-8'?>
<!DOCTYPE hibernate-configuration PUBLIC "-//Hibernate/Hibernate Configuration DTD//EN"
                                         "http://hibernate.sourceforge.net/hibernate-configuration-2.0.dtd">
<hibernate-configuration>
<session-factory>
  <property name="hibernate.connection.driver_class">oracle.jdbc.driver.OracleDriver</property>
  <property name="hibernate.connection.url">jdbc:oracle:thin:@localhost:1521:orcl</property>
  <property name="hibernate.connection.username">work</property>
  <property name="hibernate.connection.password">caecaodb</property>
  <property name="hibernate.show_sql">true</property>
  <property name="dialect">net.sf.hibernate.dialect.OracleDialect</property> 
  <property name="hibernate.connection.isloation">2</property>
 
  <mapping resource="hibernate/audit/Customer.hbm.xml"/>
  <mapping resource="hibernate/audit/AuditLogRecord.hbm.xml"/>
</session-factory>
</hibernate-configuration>
4.在包hibernate.audit下新建如下内容(附相关说明)
  接口: Auditable.java //是为了在保存日志记录到表AUDIT_LOGS时得到持久类的id.
   package hibernate.audit;
  public interface Auditable {
   public Long getId();
  }
  类AuditLogRecord.java //该类是日志表的持久久
package hibernate.audit;
import java.util.Date;
public class AuditLogRecord {
public Long entityid;
public String message;
public Class entityClass;
public Date created;
public AuditLogRecord(String message, Long entityid, Class entityClass) {
  this.message = message;
  this.entityid = entityid;
  this.entityClass = entityClass;
  this.created = new Date();
}
public AuditLogRecord() {
}
}
类:Customer.java //该类是实体类,实现了接口Auditable.java,Auditable.java主要是为了让Customer类必须有getId()方法,以便在保存日志时能得到实体类的id值
package hibernate.audit;
public class Customer implements Auditable{
Long id;
String name; 
public Customer()
{}
public Customer(String name)
{
  this.name=name;
}
public Long getId() {
  return id;
}
public void setId(Long id) {
  this.id = id;
}
public String getName() {
  return name;
}
public void setName(String name) {
  this.name = name; }
}
类:HibernateUtil.java //用于管理session
package hibernate.audit;
import net.sf.hibernate.*;
import net.sf.hibernate.cfg.Configuration;
public class HibernateUtil {
private static SessionFactory sessionFactory;
public static final ThreadLocal session= new ThreadLocal();
static {
  try {
   // 实例化一个SessionFactory对象
   //System.out.println("通过静态模块创建一个SessionFactory");
   sessionFactory = new Configuration().configure()
     .buildSessionFactory();
  } catch (HibernateException ex) {
   throw new RuntimeException("Configuration problem:"
     + ex.getMessage(), ex);
  }
}
public static Session getSession(Interceptor interceptor)  //将session和拦截器相绑定
   throws HibernateException {
  Session tempsession = (Session) session.get();
  if (tempsession == null || !tempsession.isOpen()) {
   tempsession = sessionFactory.openSession(interceptor);
   session.set(tempsession);
  }
  return tempsession;
}
public static void closeSession() throws HibernateException {
  Session s = (Session) session.get();
  if (s != null) {
   s.close();
  }
}
}
类:AutitLog.java  //该类完成日志记录的保存
  注:因为传入的session的状态不稳定,因此通过它来得到jdbc连接,再通过该jdbc连接来得到一个新的session
package hibernate.audit;
import java.sql.Connection;
import net.sf.hibernate.Session;
import net.sf.hibernate.SessionFactory;
public class AutitLog {
public static void logEvent(String message, Auditable entity,Session session) {
  Session tempSession = null;
  try {
   SessionFactory sessionFactory = session.getSessionFactory();
   Connection conn = session.connection();
   tempSession = sessionFactory.openSession(conn);   
   AuditLogRecord record=new AuditLogRecord(message,entity.getId(),entity.getClass());  
   tempSession.save(record);
   tempSession.flush();
  } catch (Exception e) {
   e.printStackTrace();
  } finally {
   try {
    tempSession.close();
   } catch (Exception e) {
    e.printStackTrace();
   }
  }
}
}

类:AuditLogIntercepor.java  //该类实现了拦截器接口,本例只实现了insert,update,delete日志,因此只在这三种数据操作的相关方法中加入了业务逻辑
package hibernate.audit;
import java.io.Serializable;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
import net.sf.hibernate.CallbackException;
import net.sf.hibernate.Interceptor;
import net.sf.hibernate.Session;
import net.sf.hibernate.type.Type;
public class AuditLogIntercepor implements Interceptor,Serializable {
private static final long serialVersionUID = 1L;
private Session session;
private Set inserts = new HashSet();
private Set updates = new HashSet();
private Set delete = new HashSet();
public void setSession(Session session) {
  this.session = session;
}
public boolean onLoad(Object arg0, Serializable arg1, Object[] arg2,
   String[] arg3, Type[] arg4) throws CallbackException {
  // TODO 自动生成方法存根
  return false;
}
//当flush()方法检查到脏对象时调用该方法
public boolean onFlushDirty(Object entity, Serializable id,
   Object[] currentState, Object[] previousState,
   String[] propertyNames, Type[] type) throws CallbackException {
  // TODO 自动生成方法存
  System.out.println("onFlushDirty()执行,传入的类为:"+entity.getClass());
  if (entity instanceof Auditable) {
   updates.add(entity);
  }
  return false;
}
//保存一个对象之前Hibernate自动调用该方法
public boolean onSave(Object entity, Serializable arg1, Object[] arg2,
   String[] arg3, Type[] arg4) throws CallbackException {
  // TODO 自动生成方法存根
  System.out.println("onSave()执行,传入的类为:"+entity.getClass());
  if (entity instanceof Auditable) {
   inserts.add(entity);
  }
  return false;
}
           //删除一个对象之前Hibernate自动调用该方法
public void onDelete(Object entity, Serializable arg1, Object[] arg2,
   String[] arg3, Type[] arg4) throws CallbackException {
  // TODO 自动生成方法存根
  System.out.println("onDelete()执行,传入的类为:"+entity.getClass());
  if (entity instanceof Auditable) {
   delete.add(entity);  } 
}
public void preFlush(Iterator arg0) throws CallbackException {
  // TODO 自动生成方法存根
}
public void postFlush(Iterator entities) throws CallbackException {
  // TODO 自动生成方法存根
  try {  
   Iterator it = updates.iterator();
   while (it.hasNext()) {
    Auditable entity = (Auditable) it.next();
    AutitLog.logEvent("update", entity, session);
   }
  
   it = inserts.iterator();
   while (it.hasNext()) {
    Auditable entity = (Auditable) it.next();
    AutitLog.logEvent("insert", entity, session);
   }
  
   it = delete.iterator();
   while (it.hasNext()) {
    Auditable entity = (Auditable) it.next();
    AutitLog.logEvent("delete", entity, session);
   }
  } catch (Exception e) {
  } finally {
   inserts.clear();
   updates.clear();
   delete.clear();
  }
}
public Boolean isUnsaved(Object arg0) {
  // TODO 自动生成方法存根
  return null;
}
public int[] findDirty(Object arg0, Serializable arg1, Object[] arg2,
   Object[] arg3, String[] arg4, Type[] arg5) {
  // TODO 自动生成方法存根
  return null;
}
public Object instantiate(Class arg0, Serializable arg1)
   throws CallbackException {
  // TODO 自动生成方法存根
  return null;
}
}
映射文件:AuditLogRecord.hbm.xml  //用于完成日志表的日志持久类的映射
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC
    "-//Hibernate/Hibernate Mapping DTD 2.0//EN"
    "http://hibernate.sourceforge.net/hibernate-mapping-2.0.dtd" >
<hibernate-mapping>
<class name="hibernate.audit.AuditLogRecord" table="audit_logs">
  <id type="long" column="ID">
   <generator class="increment"/>
  </id> 
  <property name="entityid"     type="long"      column="ENTITY_ID"     access="field" not-null="true" />
  <property name="message"      type="string"    column="MESSAGE"       access="field" not-null="true"/> 
  <property name="entityClass"  type="class"     column="ENTITY_CLASS"  access="field" not-null="true" />
  <property name="created"      type="timestamp" column="CREATED"       access="field" not-null="true"/>
</class>
</hibernate-mapping>
映射文件:Customer.hbm.xml  //用于完成customer类和customer表的映射
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
    "-//Hibernate/Hibernate Mapping DTD 2.0//EN"
    "http://hibernate.sourceforge.net/hibernate-mapping-2.0.dtd" >
<hibernate-mapping>
<class name="hibernate.audit.Customer" table="customer">
  <id name="id" type="long" column="ID">
   <generator class="increment"/>
  </id> 
  <property name="name" type="string" column="NAME" />
</class>
</hibernate-mapping>

类:HibernateTest.java  //含main()方法的入口类
package hibernate.audit;
import net.sf.hibernate.LockMode;
import net.sf.hibernate.Session;
import net.sf.hibernate.Transaction;
public class HibernateTest {
public static void main(String[] args) throws HibernateException,
   SQLException, IOException {
  new HibernateTest().doit();
}
public void doit() throws HibernateException, SQLException, IOException {
  AuditLogIntercepor interceptor = new AuditLogIntercepor();
  Session session = HibernateUtil.getSession(interceptor); //拦截器类AuditLogIntercepor要与session关联才能激发拦截器
  interceptor.setSession(session);
  Transaction tx = session.beginTransaction();
  Customer customer = new Customer("test_log");
  session.save(customer);//保存时生成日志
  customer.setName("my_log"); //更新时生成日志 
  Customer cs = (Customer) session.load(Customer.class, new Long(1),LockMode.UPGRADE);//悲观锁定;id=1的记录,在新建customer表的时候已经建立
  session.delete(cs);//删除时生成日志
  tx.commit(); 
  session.close();
}
}
最后,将HibernateTest.java以java应用程序方式运行,再看表customer已有一条id=1,name="test_log"的记录;audit_logs表中则有三条日志记录,记录了insert,update,delete

AuditLogIntercepor这个类在Hibernate3里可以继承EmptyInterceptor
1 请登录后投票
论坛首页 Java企业应用版

跳转论坛:
Global site tag (gtag.js) - Google Analytics