`
linliangyi2007
  • 浏览: 1012626 次
  • 性别: Icon_minigender_1
  • 来自: 福州
社区版块
存档分类
最新评论

分享一个简单的数据库事务拦截器

阅读更多
同大家分享一个基于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 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;
    }
	    
}
分享到:
评论
16 楼 linliangyi2007 2009-03-16  
shenrd666888 写道
spring aop中的声明事物,嗯个强大
哪里还需要自己写嘛
要站在巨人的肩膀上塞 呵呵


楼上的见笑了
15 楼 shenrd666888 2009-03-16  
spring aop中的声明事物,嗯个强大
哪里还需要自己写嘛
要站在巨人的肩膀上塞 呵呵
14 楼 fhjxp 2008-12-12  
meconsea 写道
把事务处理做成Annotation,Target=Method.这样 直接@Transcation。o(∩_∩)o...哈哈

这样就还可避免方法名前面加tx、类名后面加Biz。
13 楼 meconsea 2008-12-09  
把事务处理做成Annotation,Target=Method.这样 直接@Transcation。o(∩_∩)o...哈哈
12 楼 linliangyi2007 2008-12-09  
xucons 写道

xuyao 写道spring当初出来的时候最有名的就是AOP,声明性事务。楼主相当于自己用动态代理实现了一下,呵呵
是啊!我觉得也没有spring实现的好用

xuyao 写道

spring当初出来的时候最有名的就是AOP,声明性事务。楼主相当于自己用动态代理实现了一下,呵呵


当初一直觉得AOP实际上是破坏设计的东西,因为它必须依靠虚拟机或者类加载器注入,就没去太注意它了,呵呵
11 楼 xucons 2008-12-09  
xuyao 写道
spring当初出来的时候最有名的就是AOP,声明性事务。楼主相当于自己用动态代理实现了一下,呵呵

是啊!我觉得也没有spring实现的好用
10 楼 xuyao 2008-12-09  
spring当初出来的时候最有名的就是AOP,声明性事务。楼主相当于自己用动态代理实现了一下,呵呵
9 楼 daquan198163 2008-12-08  
linliangyi2007 写道
daquan198163 写道

spring提供了现成的org.springframework.transaction.interceptor.TransactionProxyFactoryBean和org.springframework.orm.hibernate3.HibernateTransactionManager不能满足你们的要求吗?

楼上的不厚道,我确实不知道这些类,你知道了说一声啊!大家共享是好事,显摆自己知道“回”字的四种写法就不好了。
要知道中国13亿,牛人多了去了

莫名其妙,我这不是告诉你了么
怎么就成了显摆了?
8 楼 linliangyi2007 2008-12-08  
daquan198163 写道

linliangyi2007 写道endeavor416 写道
lz有没有简单的测试代码啊?

晕,我们是直接用于项目中的,所以没有什么测试啊



我的意思是,没有专门针对这两个类的的测试代码,不是没有做测试!晕死
7 楼 linliangyi2007 2008-12-08  
daquan198163 写道

spring提供了现成的org.springframework.transaction.interceptor.TransactionProxyFactoryBean和org.springframework.orm.hibernate3.HibernateTransactionManager不能满足你们的要求吗?

楼上的不厚道,我确实不知道这些类,你知道了说一声啊!大家共享是好事,显摆自己知道“回”字的四种写法就不好了。
要知道中国13亿,牛人多了去了
6 楼 sdh5724 2008-12-07  
都是成熟的技术, 要什么测试。 这个声明事务也是用于小系统, 如果大型系统还是要谨慎的。
5 楼 gembler 2008-12-07  
linliangyi2007 写道
endeavor416 写道

lz有没有简单的测试代码啊?


晕,我们是直接用于项目中的,所以没有什么测试啊


在项目中用不是更应该有测试吗?
4 楼 daquan198163 2008-12-07  
spring提供了现成的org.springframework.transaction.interceptor.TransactionProxyFactoryBean和org.springframework.orm.hibernate3.HibernateTransactionManager
不能满足你们的要求吗?
3 楼 daquan198163 2008-12-07  
linliangyi2007 写道
endeavor416 写道

lz有没有简单的测试代码啊?

晕,我们是直接用于项目中的,所以没有什么测试啊

2 楼 linliangyi2007 2008-12-07  
endeavor416 写道

lz有没有简单的测试代码啊?


晕,我们是直接用于项目中的,所以没有什么测试啊
1 楼 endeavor416 2008-12-06  
lz
有没有简单的测试代码啊?

相关推荐

    SpringMVC入门+myBatis简单示例分享

    它提供了一个分发请求的调度器,将请求转发到适当的控制器,处理业务逻辑后返回响应。 2. **工作流程**: - 请求到达DispatcherServlet(前端控制器)。 - DispatcherServlet根据请求信息找到相应的...

    NHIBERNATE - 符合.Net习惯的关系数据库持久化

    NHibernate 是一个强大的开源对象关系映射(ORM)框架,专为.NET平台设计。它允许开发者用面向对象的方式来处理数据库,而无需关心底层SQL语句的编写,极大地提高了开发效率和代码可维护性。本资源提供了最新最全的...

    JavaEE源码企业合同系统源码数据库sql文档

    - **拦截器模型**: Struts 2使用拦截器来处理请求和响应,这种方式使得代码更加模块化。 - **强大的表单标签库**: Struts 2提供了一系列丰富的标签库,可以方便地创建表单和处理用户输入。 - **集成性**: 它可以轻松...

    基于ssm微信小程序的短视频系统源码数据库.zip

    标题中的“基于ssm微信小程序的短视频系统源码数据库”表明这是一个使用SSM(Spring、SpringMVC、MyBatis)框架开发的项目,目的是构建一个与微信小程序对接的短视频分享平台。SSM是Java Web开发中常用的三层架构,...

    seata-server-1.1.0.tar.gz

    【seata-server-1.1.0.tar.gz】是一个包含Seata Server 1.1.0版本的压缩包文件,通常在GitHub等平台上下载可能受到速度限制,因此这个分享提供了一个更快的获取途径。Seata是阿里巴巴开源的一款分布式事务解决方案,...

    基于springboot的厨艺交流平台源码数据库.zip

    首先,"基于SpringBoot的厨艺交流平台"是一个旨在连接热爱烹饪的人们,分享菜谱、交流心得的在线社区。SpringBoot简化了Spring的应用开发,提供了自动配置、内嵌Web服务器等功能,使得开发者可以更快地启动和运行...

    sharefive所分享的mybatis的jar包

    MyBatis是一个优秀的Java持久层框架,它支持定制化SQL、存储过程以及高级映射。MyBatis避免了几乎所有的JDBC代码和手动设置参数以及获取结果集。MyBatis可以使用简单的XML或注解进行配置和原始映射,将接口和Java的...

    Spring框架实用知识库分享

    * 介绍Spring Boot中的统一功能处理,包括拦截器、过滤器、监听器等 * 演示如何使用Spring Boot的统一功能处理来实现功能扩展 * 介绍如何使用Spring Boot的统一功能处理来实现日志记录、安全控制等功能 第13篇 ...

    3大框架整合的一个例子分享给大家

    在Struts2中,一个请求会经过一系列拦截器,这些拦截器可以执行验证、登录检查等功能,最后由Action处理业务逻辑,返回结果到视图层。Struts2的配置灵活,支持多种结果类型和模板技术,如JSP、FreeMarker等。 整合...

    基于SSM框架的外卖跑腿系统源码+数据库+文档.rar

    请求通过DispatcherServlet分发,经过一系列拦截器,最终到达Controller,处理完成后返回ModelAndView对象,再由视图解析器渲染结果。 3. **Mybatis**:Mybatis是一个轻量级的ORM(Object-Relational Mapping)框架...

    在线教育系统.rar

    它的主要优点是提供了强大的拦截器机制,可以方便地添加全局或特定于动作的逻辑,如登录验证、权限控制等。此外,Struts2支持多种结果类型和模板技术,使视图层的实现更加灵活。 Spring框架则负责管理应用中的对象...

    一个struts2+hibernate+spring整合的例子

    Hibernate是一个强大的对象关系映射(ORM)工具,它简化了数据库操作;而Spring框架则是一个全面的后端解决方案,提供了依赖注入、事务管理、AOP(面向切面编程)等功能。 在这个"Struts2+Hibernate+Spring整合的...

    进销存java源代码分享

    在这个“进销存java源代码分享”中,我们看到的是一个基于JAVA编程语言,结合EXTJS前端框架以及SSH(Struts2、Spring、Hibernate)后端框架实现的系统。这个开源项目为软件开发者提供了一个学习和二次开发的平台。 ...

    初学者blog系统-javaweb.zip

    这是一个针对初学者设计的基于JavaWeb的博客系统项目,名为"BBSdemo",它封装在一个名为"初学者blog系统-javaweb.zip"的压缩包里。该项目采用经典的SSH(Struts2、Hibernate和Spring)框架,这是一套在早期Web开发中...

    简单的ORM框架Known.DLite.zip

    Known.DLite可能设计为模块化和可扩展的,允许开发者根据项目需求添加自定义行为,如自定义类型转换、拦截器等。这增强了框架的灵活性,使其能适应不同的业务场景。 6. **数据迁移**: 对于开发过程中的数据库...

    一个游戏bbs论坛系统_标准的struts2+hibernate+spring三大框架

    **Hibernate** 是一个对象关系映射(ORM)框架,它简化了数据库操作,允许开发者用面向对象的方式来处理数据库事务。在Java应用中,Hibernate自动管理数据库的CRUD(创建、读取、更新和删除)操作,通过XML配置文件...

    TeenMusic在线音乐分享系统 | JavaWeb项目开发使用了SSH框架

    总结起来,"TeenMusic在线音乐分享系统"是一个基于SSH框架的JavaWeb项目,它展示了如何运用这些技术构建一个功能完善的音乐分享平台。对于想要提升JavaWeb开发技能的程序员,这个项目提供了一个实际操作的学习资源,...

    分享计算机毕业设计-双鱼林SSM图书信息管理系统

    5 spring容器内部使用拦截器,以Spring AOP的方式实现事务控制管理。 系统实体对象: 图书类型:图书类别,类别名称,可借阅天数 图书:图书条形码,图书名称,图书所在类别,图书价格,库存,出版社,图书图片

    SSM框架源码分享 非常简洁思路清晰

    2. **SpringMVC配置**:如DispatcherServlet的配置、视图解析器的设置、拦截器的使用等。 3. **MyBatis配置**:MyBatis的SqlSessionFactory配置,Mapper接口的定义,XML映射文件中的SQL语句编写。 4. **SSM整合**:...

    struts2 info

    2. "hibernate_reference.pdf":这可能是Hibernate ORM框架的参考指南,Hibernate是一个流行的Java持久层解决方案,使得开发者可以更加便捷地操作数据库。它提供了对象-关系映射(ORM)功能,允许开发者使用Java对象...

Global site tag (gtag.js) - Google Analytics