锁定老帖子 主题:分享一个简单的数据库事务拦截器
精华帖 (0) :: 良好帖 (3) :: 新手帖 (11) :: 隐藏帖 (2)
|
|
---|---|
作者 | 正文 |
发表时间:2008-12-06
背景: 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 HibernateUtil() { } /** * Returns the ThreadLocal Session instance. Lazy initialize * the <code>SessionFactory</code> if needed. * * @return Session * @throws HibernateException */ public static Session getSession() throws HibernateException { Session session = (Session) localSession.get(); if (session == null || !session.isOpen()) { if (sessionFactory == null) { rebuildSessionFactory(); } session = (sessionFactory != null) ? sessionFactory.openSession() : null; localSession.set(session); } return session; } /** * Rebuild hibernate session factory * */ public static void rebuildSessionFactory() { try { configuration.configure(configFile); sessionFactory = configuration.buildSessionFactory(); } catch (Exception e) { System.err.println("%%%% Error Creating SessionFactory %%%%"); e.printStackTrace(); } } /** * Close the single hibernate session instance. * * @throws HibernateException */ public static void closeSession() throws HibernateException { Session session = (Session) localSession.get(); localSession.set(null); if (session != null && session.isOpen()) { session.close(); } } /** * return session factory * */ public static SessionFactory getSessionFactory() { return sessionFactory; } /** * return session factory * * session factory will be rebuilded in the next call */ public static void setConfigFile(String configFile) { HibernateUtil.configFile = configFile; sessionFactory = null; } /** * return hibernate configuration * */ public static Configuration getConfiguration() { return configuration; } /** * 开始当前线程中Hibernate Session的事务 * @return Transaction * @throws HibernateException */ public static Transaction beginTransaction() throws HibernateException { Transaction tx = (Transaction)localTransaction.get(); if(tx == null || tx.wasCommitted() || tx.wasRolledBack()){ Session session = getSession(); tx = (session != null) ? session.beginTransaction() : null; localTransaction.set(tx); } return tx; } /** * 提交当前线程中Hibernate Session的事务 * @throws HibernateException */ public static void commitTransaction() throws HibernateException { Transaction tx = (Transaction)localTransaction.get(); localTransaction.set(null); if(tx != null || (!tx.wasCommitted() && !tx.wasRolledBack())){ tx.commit(); } } /** * 回滚当前线程中Hibernate Session的事务 * @throws HibernateException */ public static void rollbackTransaction() throws HibernateException { Transaction tx = (Transaction)localTransaction.get(); localTransaction.set(null); if(tx != null || (!tx.wasCommitted() && !tx.wasRolledBack())){ tx.rollback(); } } /** * 当前Hibernate Session是否打开 * @return */ public static boolean isOpenSession() { Session session = (Session) localSession.get(); if (session != null && session.isOpen()) { return true; } return false; } } 声明:ITeye文章版权属于作者,受法律保护。没有作者书面许可不得转载。
推荐链接
|
|
返回顶楼 | |
发表时间:2008-12-06
lz
有没有简单的测试代码啊? |
|
返回顶楼 | |
发表时间:2008-12-07
endeavor416 写道 lz有没有简单的测试代码啊? 晕,我们是直接用于项目中的,所以没有什么测试啊 |
|
返回顶楼 | |
发表时间:2008-12-07
linliangyi2007 写道 endeavor416 写道 lz有没有简单的测试代码啊? 晕,我们是直接用于项目中的,所以没有什么测试啊 |
|
返回顶楼 | |
发表时间:2008-12-07
spring提供了现成的org.springframework.transaction.interceptor.TransactionProxyFactoryBean和org.springframework.orm.hibernate3.HibernateTransactionManager
不能满足你们的要求吗? |
|
返回顶楼 | |
发表时间:2008-12-07
linliangyi2007 写道 endeavor416 写道 lz有没有简单的测试代码啊? 晕,我们是直接用于项目中的,所以没有什么测试啊 在项目中用不是更应该有测试吗? |
|
返回顶楼 | |
发表时间:2008-12-07
都是成熟的技术, 要什么测试。 这个声明事务也是用于小系统, 如果大型系统还是要谨慎的。
|
|
返回顶楼 | |
发表时间:2008-12-08
daquan198163 写道 spring提供了现成的org.springframework.transaction.interceptor.TransactionProxyFactoryBean和org.springframework.orm.hibernate3.HibernateTransactionManager不能满足你们的要求吗? 楼上的不厚道,我确实不知道这些类,你知道了说一声啊!大家共享是好事,显摆自己知道“回”字的四种写法就不好了。 要知道中国13亿,牛人多了去了 |
|
返回顶楼 | |
发表时间:2008-12-08
daquan198163 写道 linliangyi2007 写道endeavor416 写道 lz有没有简单的测试代码啊? 晕,我们是直接用于项目中的,所以没有什么测试啊 我的意思是,没有专门针对这两个类的的测试代码,不是没有做测试!晕死 |
|
返回顶楼 | |
发表时间:2008-12-08
linliangyi2007 写道 daquan198163 写道 spring提供了现成的org.springframework.transaction.interceptor.TransactionProxyFactoryBean和org.springframework.orm.hibernate3.HibernateTransactionManager不能满足你们的要求吗? 楼上的不厚道,我确实不知道这些类,你知道了说一声啊!大家共享是好事,显摆自己知道“回”字的四种写法就不好了。 要知道中国13亿,牛人多了去了 莫名其妙,我这不是告诉你了么 怎么就成了显摆了? |
|
返回顶楼 | |