日期:2014-05-16  浏览次数:20368 次

分享一个简单的数据库事务拦截器
同大家分享一个基于Spring的Hibernate数据库会话及事务拦截器。
背景:
1.Hibernate的Session和Transaction的开关是很烦人的一件事,我们希望有一个拦截器能自动的在我们需要的时候打开session或者transaction,并且在相应方法结束的时候自动关闭
2.Open Session In View是Hibernate官网上推荐的使用Servlet Filter对Session的控制的方式,对一般的web应用还不错,但要用于企业的SOA分布应用就比较困难了
3.如何实现Transaction的自动开关呢?还要考虑到业务方法的嵌套调用,事务的边界是不确定的情况。

下面的这两个类给出了一种简单的解决方式,在实际应用中能提高不少编程效率。

使用条件:
1.使用Spring拦截器,配置你要拦截的类
(我的使用方式是,所有业务逻辑层的类都以Biz做结尾,进行拦截)
2.所有事务性的方法以tx开头


package org.wltea.util;

import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;

import org.wltea.sql.hibernate.HibernateUtil;

/**
 * Hibernate的事务拦截器,通过配置文件自动完成Hibernate的事务
 * 
 * @author linliangyi , zhuoshiyao
 * 
 */
public class TransactionInterceptor implements MethodInterceptor {
	
	private ThreadLocal<Integer> lockDeep = new ThreadLocal<Integer>();

	public Object invoke(MethodInvocation arg0) throws Throwable {
		Object result = null;
		String methodName = arg0.getMethod().getName();

		boolean isBeginTransaction = false;//是否需要开事务
		
		try {
			//判断是否需要事务
			if (methodName.startsWith("tx")) {
				//线程变量中事务数加1
				Integer deep = lockDeep.get();
				if (deep == null || deep.intValue() == 0) {
					deep = new Integer(1);
				} else {
					deep = new Integer(deep.intValue() + 1);
				}
				lockDeep.set(deep);
				HibernateUtil.beginTransaction();//开始事务
				isBeginTransaction = true;//标志事务已打开

			}
			
			//执行业务逻辑方法
			result = arg0.proceed();

			if (isBeginTransaction) {

				//线程变量
				int deep = lockDeep.get().intValue();
				deep = deep - 1;
				if (deep == 0) {
					HibernateUtil.commitTransaction();//提交事务
				}
				//若正常提交事务,线程变量中事务数减1
				lockDeep.set(new Integer(deep));

			}
		} catch(Exception e) {
			if (isBeginTransaction) {

				//线程变量
				int deep = lockDeep.get().intValue();
				deep = deep - 1;
				//线程变量中事务数减1
				lockDeep.set(new Integer(deep));
				
				HibernateUtil.rollbackTransaction();//异常则回滚DB事务

			}

			throw e;

		} finally {
			Integer deep = lockDeep.get();
			if (deep == null || deep.intValue() == 0) {
				HibernateUtil.closeSession();//如果上下文有开启的session,关闭session
			}
		}

		return result;
	}
}







以下是辅助工具类,来自Hibernate官网的,做了些修改和注释
package org.wltea.sql.hibernate;

import org.hibernate.HibernateException;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.cfg.Configuration;

/**
 * 
 * Hibernate工具类
 * 
 * 单子模式类
 * 提供了方便的,静态的session及Transaction获取,关闭方法。
 * 使用ThreadLocal对象维护session在一个线程操作(通常也是事务操作)中的唯一性
 * 
 * Configures and provides access to Hibernate sessions, tied to the
 * current thread of execution.  Follows the Thread Local Session
 * pattern, see {@link http://hibernate.org/42.html }.
 */
public class HibernateUtil {

    /** 
     * Location of hibernate.cfg.xml file.
     * Location should be on the classpath as Hibernate uses  
     * #resourceAsStream style lookup for its configuration file. 
     * The default classpath location of the hibernate config file is 
     * in the default package. Use #setConfigFile() to update 
     * the location of the configuration file for the current session.   
     */
    private static String CONFIG_FILE_LOCATION = "/hibernate.cfg.xml";
	private static final ThreadLocal localSession = new ThreadLocal();
	private static final ThreadLocal localTransaction = new ThreadLocal();
    private  static Configuration configuration = new Configuration();
    private static SessionFactory sessionFactory;
    private static String configFile = CONFIG_FILE_LOCATION;

	static {
    	try {
			configuration.configure(configFile);
			sessionFactory = configuration.buildSessionFactory();
		} catch (Exception e) {
			System.err
					.println("%%%% Error Creating SessionFactory %%%%");
			e.printStackTrace();
		}
    }
    private HibernateUti