Hibernate的回調與攔截

在Hibernate中,有兩種方式能夠捕獲實體對象的GRUD操做並執行相應的處理java

Hibernate回調(org.hibernate.classic.Lifecycle接口):sql

//Provides callbacks from the Session to the persistent object.
//Persistent classes may implement this interface but they are not
//required to.
//If a CallbackException is thrown, the operation is vetoed and the
//exception is passed back to the application.
public interface Lifecycle {
	
	//If onSave(), onUpdate() or onDelete() return VETO,
	//the operation is silently vetoed.
	public static final boolean VETO = true;
	public static final boolean NO_VETO = false;

	//Called just before the object is saved
	public boolean onSave(Session s) throws CallbackException;

	//Called when an entity is passed to Session.update().
	//This method is not called every time the object's
	//state is persisted during a flush.
	public boolean onUpdate(Session s) throws CallbackException;

	//Called just before an object is deleted
	public boolean onDelete(Session s) throws CallbackException;

	//Called just after an object is loaded
	public void onLoad(Session s, Serializable id);
}

須要注意的地方:安全

1,若是onSave()、onUpdate()、onDelete()方法返回VOTE(true)或者在以上方法中拋出了CallbackException異常,操做將會中止而不會調用以後的Session.save()、Session.update()、Session.delete()方法session

2,並非每次調用Session.update()方法以前都會調用onUpdate()方法併發

3,調用Session.get()方法會直接返回實體對象,故在調用該方法後會當即調用onload()方法,而調用Session.load()方法返回的是實體對象的代理,故在調用該方法後不會當即調用onload()方法,對象在第一次使用時纔會真正加載,而在對象真正加載完成以後纔會調用onload()方法app

4,不能直接使用方法中的Session對象,該方法是由當前Session負責調用,若是在這些方法中又調用當前Session進行持久化,將致使Session內部狀態混亂ide

在onSave()方法中調用Session.save()方法將會致使死循環,可是在onSave()方法中執行Session.update()方法卻沒有報異常,不過一般方法只負責記錄日誌,數據合法性校驗等簡單工做,不會在這裏再次調用Session對象完成數據持久化,故不需考慮太多post

提到Lifecycle接口,一般也要提到Validatable接口(org.hibernate.classic.Validatable):ui

//Implemented by persistent classes with invariants that must
//be checked before inserting into or updating the database.
public interface Validatable {
	
	//Validate the state of the object before persisting it.
	//If a violation occurs, throw a ValidationFailure.
	//This method must not change the state of the object by
	//side-effect.
	public void validate() throws ValidationFailure;
}

只有在對象插入和對象更新時纔會調用validate()方法對對象數據合法性進行校驗this

public class User implements Serializable,Lifecycle,Validatable{
	private Integer id;
	private String name;
	private Integer age;
	private static final long serialVersionUID = 1L;
	
	public User(){}
	
	public Integer getId() {
		return id;
	}
	
	public void setId(Integer id) {
		this.id = id;
	}
	
	public String getName() {
		return name;
	}
	
	public void setName(String name) {
		this.name = name;
	}
	
	public Integer getAge() {
		return age;
	}
	
	public void setAge(Integer age) {
		this.age = age;
	}

	public boolean onSave(Session s) throws CallbackException {
		System.out.println("********on save********");
		System.out.println("id :" + id);
		System.out.println("name :" + name);
		System.out.println("age :" + age);
		return Lifecycle.NO_VETO;
	}

	@Override
	public boolean onUpdate(Session s) throws CallbackException {
		System.out.println("********on update********");
		System.out.println("id :" + id);
		System.out.println("name :" + name);
		System.out.println("age :" + age);
		return Lifecycle.VETO;
	}

	@Override
	public boolean onDelete(Session s) throws CallbackException {
		System.out.println("********on delete********");
		throw new CallbackException("Delete operation is not allowed!");
	}

	@Override
	public void onLoad(Session s, Serializable id) {
		System.out.println("********on load********");
		System.out.println("id :" + id);
	}

	@Override
	public void validate() throws ValidationFailure {
		System.out.println("~~~~~~~~valid~~~~~~~~");
		if(id < 0)
			throw new ValidationFailure("Illegal id!");
		if(name == null || name.equals(""))
			throw new ValidationFailure("Illegal name!");
		if(age < 0 || age > 150)
			throw new ValidationFailure("Illegal age!");
	}
}

因爲這種方式對POJO帶有侵入性,因此不建議使用

 

Hibernate攔截(org.hibernate.Interceptor接口):

接口定義了很是多的方法,基本上經過命名就能夠看出其功能,就不一一介紹了

不建議直接繼承Interceptor接口,更好的方式是繼承EmptyInterceptor類,並重寫須要的方法,EmptyInterceptor接口以下:

public class EmptyInterceptor implements Interceptor, 
		Serializable {
	
	public static final Interceptor INSTANCE = 
		new EmptyInterceptor();
	
	protected EmptyInterceptor() {}

	public void onDelete(
			Object entity, 
			Serializable id, 
			Object[] state, 
			String[] propertyNames, 
			Type[] types) {}

	public boolean onFlushDirty(
			Object entity, 
			Serializable id, 
			Object[] currentState, 
			Object[] previousState, 
			String[] propertyNames, 
			Type[] types) {
		return false;
	}

	public boolean onLoad(
			Object entity, 
			Serializable id, 
			Object[] state, 
			String[] propertyNames, 
			Type[] types) {
		return false;
	}

	public boolean onSave(
			Object entity, 
			Serializable id, 
			Object[] state, 
			String[] propertyNames, 
			Type[] types) {
		return false;
	}

	public void postFlush(Iterator entities) {}
	
	public void preFlush(Iterator entities) {}

	public Boolean isTransient(Object entity) {
		return null;
	}

	public Object instantiate(String entityName, EntityMode entityMode, 
			Serializable id) {
		return null;
	}

	public int[] findDirty(Object entity,
			Serializable id,
			Object[] currentState,
			Object[] previousState,
			String[] propertyNames,
			Type[] types) {
		return null;
	}

	public String getEntityName(Object object) {
		return null;
	}

	public Object getEntity(String entityName, Serializable id) {
		return null;
	}

	public void afterTransactionBegin(Transaction tx) {}

        public void afterTransactionCompletion(Transaction tx) {}

	public void beforeTransactionCompletion(Transaction tx) {}

	public String onPrepareStatement(String sql) {
		return sql;
	}

	public void onCollectionRemove(Object collection, Serializable key) 
			throws CallbackException {}

	public void onCollectionRecreate(Object collection, Serializable key) 
			throws CallbackException {}

	public void onCollectionUpdate(Object collection, Serializable key) 
			throws CallbackException {}	
}

示例以下:

public class LogInterceptor extends EmptyInterceptor {

	private static final long serialVersionUID = 1L;

	@Override
	public boolean onLoad(Object entity, Serializable id, Object[] state,
			String[] propertyNames, Type[] types) {
		System.out.println(entity.getClass().getName() + " loaded.");
		return false;
	}
}

值得注意的是能夠配置2種範圍的攔截器

SessionFactory範圍的攔截器:

因爲多個Session可能併發的使用SessionFactoruy範圍的攔截器,故該攔截器必須是線程安全的

LogInterceptor li = new LogInterceptor();
Configuration conf = new Configuration().setInterceptor(li);  
SessionFactory sessionFactory = conf.configure().buildSessionFactory();
        
Session sess = sessionFactory.openSession();

Session範圍的攔截器:

LogInterceptor li = new LogInterceptor();
Configuration conf = new Configuration();  
SessionFactory sessionFactory = conf.configure().buildSessionFactory();
        
Session sess = sessionFactory.openSession(li);
相關文章
相關標籤/搜索