`
jamesby
  • 浏览: 383407 次
  • 性别: Icon_minigender_1
社区版块
存档分类
最新评论

自己实现的TransactionManager

    博客分类:
  • Java
阅读更多
背景:
目前有一个系统,系统已经写好了,但是要不停的添加新的功能,用Struts,
业务逻辑写在Action中,以后可能增加一层Service。
业务处理和持久层没有使用任何框架,目前是用Dao担任业务处理加持久层双重操作,
但是有些业务处理很复杂,固设计了一个事务处理框架,大家帮我看下有没有线程安全的问题,
第一次使用ThreadLocal,请多指教。


Connection Holder 代码

public class ConnectionHolder {
	private Connection connection = null;
	private boolean rollback = false;
	private boolean isreadonly = false;
	
	public boolean isIsreadonly() {
		return isreadonly;
	}

	public void setIsreadonly(boolean isreadonly) {
		this.isreadonly = isreadonly;
	}
	public Connection getConnection() {
		if (null == connection)
			throw new RuntimeException("connection not exist........");
		return connection;
	}

	public void setConnection(Connection connection) {
		this.connection = connection;
	}

	public boolean isRollback() {
		return rollback;
	}

	public void setRollback(boolean rollback) {
		this.rollback = rollback;
	}
}

TransactionManager 代码
public class TransactionManager {
	private static final Log logger = LogFactory
			.getLog(TransactionManager.class);

	private static ThreadLocal _thread = new ThreadLocal();

	private static void safeCloseConnection(Connection con) {
		try {
			if (null != con)
				con.close();
			con = null;
		} catch (Exception e) {
			logger.error("", e);
		}
	}

	public static void begin() {
		begin(false);
	}

	public static void begin(boolean isReadonly) {
		ConnectionHolder holder = null;
		Connection con = null;
		try {
			con = JNDIUtils.getConnection();

			if (!isReadonly) {
				con.setAutoCommit(false);
			}

			holder = new ConnectionHolder();
			holder.setConnection(con);
			holder.setIsreadonly(isReadonly);

			_thread.set(holder);
		} catch (Exception e) {
			safeCloseConnection(con);
			logger.error("", e);
			throw new RuntimeException();
		}
	}

	private static void commit() {
		ConnectionHolder holder = null;
		Connection con = null;
		try {
			holder = getConnectionHolder();
			con = holder.getConnection();
			if (!holder.isRollback() && !holder.isIsreadonly()) {
				con.commit();
				con.setAutoCommit(true);
			}
		} catch (Exception e) {
			logger.error("", e);
		} finally {
			safeCloseConnection(con);
		}
	}

	public static void end() {
		commit();
	}

	public static void rollback() {
		ConnectionHolder holder = null;
		Connection con = null;
		try {
			holder = getConnectionHolder();
			holder.setRollback(true);
			con = holder.getConnection();
			if (holder.isIsreadonly()) {
				throw new RuntimeException("readonly cannot rollback....");
			}
			con.rollback();
			con.setAutoCommit(true);
		} catch (RuntimeException e) {
			throw e;
		} catch (Exception e) {
			logger.error("", e);
		} finally {
			safeCloseConnection(con);
		}
	}

	private static ConnectionHolder getConnectionHolder() {
		ConnectionHolder holder = (ConnectionHolder) _thread.get();
		if (null != holder)
			return holder;
		throw new RuntimeException("connection holder not exist.......");
	}

	public static Connection openConnection() {
		Connection con = getConnectionHolder().getConnection();
		if (null != con)
			return con;
		throw new RuntimeException("connection not exist.......");
	}
}


Action 部分代码

public ActionForward deleteResourceXqzy(ActionMapping mapping,
		ActionForm form, HttpServletRequest request,
		HttpServletResponse response) {
	try {
		TransactionManager.begin(); //事务开始
		/**
			多次DAO代码调用
			业务处理
			多次DAO代码调用
		*/
	} catch (Exception ex) {
		TransactionManager.rollback(); //事务回滚
		//其它操作
	} finally {
		TransactionManager.end(); //事务提交
		//其它操作
	}
	return mapping.findForward("test");
}


DAO 部分代码

public static void deleteResourceZyfb() throws Exception {
	String sql = null;
	PreparedStatement ps = null;
	try {
		Connection con = TransactionManager.openConnection();
		sql = "";
		ps = con.prepareStatment(sql);
		ps.executeUpdate();
	} finally {
		safeCloseStatementOrRs(ps);
	}
}
分享到:
评论
9 楼 icefire 2007-04-12  
有个问题,在end的同时,是否应该ThreadLocal.remove()呢?
8 楼 icefire 2007-04-09  
正在做毕业设计,不想引入Spring,时间不够,学不过来。
就借用下!!

PS:我会保留版权信息的!呵呵!
7 楼 jamesby 2007-02-28  
JAVA_ED 写道

ServiceA(){
   try{
      begin();
      ServiceB();
      .....
   }
}

你可以去参考一下一些OpenSrc Project的TransactionManager如何实现



事务有三个方面要考虑,隔离级别、传递方式和readonly,隔离级别目前默认,传递方式就是楼上说的这个.

这样的情况还没有考虑,如果考虑目前的想法是加入一个计数器,begin 时 count++,rollback 时 如果 count>1 throw exception count--,否则rollback,

commit时如果count>1 count-- 否则commit.

项目现在紧急,没有时间,我考虑的是TransactionManager这个类的接口稳定,至于如何是最合理最优化的实现,以后再说,先弄个Demo类的东西先跑起来.
6 楼 JAVA_ED 2007-02-27  
jamesby 写道
JAVA_ED 写道
jamesby 写道
to JAVA_ED:

什么意思,能否详细说明一下?
不new ConnectionHolder()那用同一个ConnectionHolder?


nested transaction? 所谓ConnectionHolder应该是个Connection Container
如果每次begin都去新开个connection, 那前一次的不是丢失了吗
这样不如把connection直接绑上去


但是我的使用代码是这样的啊,也就是每个Service Method 只使用一个Connection!

public ActionForward methodName(ActionMapping mapping,   
        ActionForm form, HttpServletRequest request,   
        HttpServletResponse response) {   
    try {   
        TransactionManager.begin(); //事务开始   
        /**  
            多次DAO代码调用  
            业务处理  
            多次DAO代码调用  
        */  
    } catch (Exception ex) {   
        TransactionManager.rollback(); //事务回滚   
        //其它操作   
    } finally {   
        TransactionManager.end(); //事务提交   
        //其它操作   
    }   
    return mapping.findForward("test");   
}


第一个版本我是将Connection绑上去的,但是后来多了readonly和rollback两个状态,所以弄了这个Holder的.



ServiceA(){
   try{
      begin();
      ServiceB();
      .....
   }
}

你可以去参考一下一些OpenSrc Project的TransactionManager如何实现

5 楼 jamesby 2007-02-27  
JAVA_ED 写道
jamesby 写道
to JAVA_ED:

什么意思,能否详细说明一下?
不new ConnectionHolder()那用同一个ConnectionHolder?


nested transaction? 所谓ConnectionHolder应该是个Connection Container
如果每次begin都去新开个connection, 那前一次的不是丢失了吗
这样不如把connection直接绑上去


但是我的使用代码是这样的啊,也就是每个Service Method 只使用一个Connection!

public ActionForward methodName(ActionMapping mapping,   
        ActionForm form, HttpServletRequest request,   
        HttpServletResponse response) {   
    try {   
        TransactionManager.begin(); //事务开始   
        /**  
            多次DAO代码调用  
            业务处理  
            多次DAO代码调用  
        */  
    } catch (Exception ex) {   
        TransactionManager.rollback(); //事务回滚   
        //其它操作   
    } finally {   
        TransactionManager.end(); //事务提交   
        //其它操作   
    }   
    return mapping.findForward("test");   
}


第一个版本我是将Connection绑上去的,但是后来多了readonly和rollback两个状态,所以弄了这个Holder的.

4 楼 JAVA_ED 2007-02-27  
jamesby 写道
to JAVA_ED:

什么意思,能否详细说明一下?
不new ConnectionHolder()那用同一个ConnectionHolder?


nested transaction? 所谓ConnectionHolder应该是个Connection Container
如果每次begin都去新开个connection, 那前一次的不是丢失了吗
这样不如把connection直接绑上去
3 楼 jamesby 2007-02-27  
to JAVA_ED:

什么意思,能否详细说明一下?
不new ConnectionHolder()那用同一个ConnectionHolder?
2 楼 JAVA_ED 2007-02-27  
jamesby 写道
如果以上是成熟的,无线程安全性问题,也可以考虑实现一个TransactionTemplate,代码类似下面这个.

TransactionTemplate

public void execute() throws Exception{
    try
    {
        TransactionManager.begin();
        process();
    }catch(Exception ex){
        TransactionManager.rollback();
        throw e;
    }finally{
        TransactionManager.end();
    }
}
abstract protected void process() throws Exception{}


Action 部分代码

public ActionForward deleteResourceXqzy(ActionMapping mapping,   
        ActionForm form, HttpServletRequest request,   
        HttpServletResponse response) {   
    try {   
               new TransactionTemplate() {
				public void process() {
									}
	     }.execute();
    } catch (Exception ex) {   

    }
    return mapping.findForward("test");   
}  


其实Spring已经有了很完善的功能,不过目前不想对老系统使用Spring!还望大家多给意见,哪些设计的不合理,尤其是线程安全性方面的.当然上面的代码并没有对异常体系进行设计!还是比较习惯使用Exception和RuntimeException这两个异常.


你把ConnectionHolder绑到ThreadLocal  然后每次再去new一个ConnectionHolder再绑一次?
1 楼 jamesby 2007-02-23  
如果以上是成熟的,无线程安全性问题,也可以考虑实现一个TransactionTemplate,代码类似下面这个.

TransactionTemplate

public void execute() throws Exception{
    try
    {
        TransactionManager.begin();
        process();
    }catch(Exception ex){
        TransactionManager.rollback();
        throw e;
    }finally{
        TransactionManager.end();
    }
}
abstract protected void process() throws Exception{}


Action 部分代码

public ActionForward deleteResourceXqzy(ActionMapping mapping,   
        ActionForm form, HttpServletRequest request,   
        HttpServletResponse response) {   
    try {   
               new TransactionTemplate() {
				public void process() {
									}
	     }.execute();
    } catch (Exception ex) {   

    }
    return mapping.findForward("test");   
}  


其实Spring已经有了很完善的功能,不过目前不想对老系统使用Spring!还望大家多给意见,哪些设计的不合理,尤其是线程安全性方面的.当然上面的代码并没有对异常体系进行设计!还是比较习惯使用Exception和RuntimeException这两个异常.

相关推荐

    开源项目-Code-Hex-sqlx-transactionmanager.zip

    Transaction manager 在 sqlx 的基础上实现了事务管理,使得在复杂的业务逻辑中处理数据库事务更为容易。 1. **sqlx 库介绍** sqlx 提供了比 `database/sql` 更高级别的抽象,它支持结构化绑定,允许开发者将 SQL ...

    springboot整合mybatis配置多数据源

    Spring Boot默认使用JpaTransactionManager,但这里我们需要MyBatis的SqlSessionTemplate,所以使用`@EnableTransactionManagement`和`@Bean`创建MyBatis的TransactionManager。 6. **Mapper配置** 需要为每个数据...

    spring基于AOP实现事务

    本文将深入探讨如何基于AOP(面向切面编程)来实现Spring的事务管理,特别是通过TransactionProxyFactoryBean。让我们一起探索这个主题。 首先,了解什么是AOP。AOP是Spring框架的核心特性,它允许我们在不修改业务...

    spring+druid+AtomikosDataSource实现多数据源切换及分布式事务控制

    创建多数据源的配置文件,包括AtomikosDataSourceBean的定义、TransactionManager的配置以及DynamicRoutingDataSource的实现。在业务代码中,通过`@Transactional`注解开启分布式事务,并在必要时使用`ThreadLocal`...

    dbutils封装ORM 实现BaseDAO

    4. **TransactionManager**: dbutils还提供了事务管理功能,通过TransactionManager可以方便地进行数据库事务的控制,实现事务的开始、提交、回滚等操作。 `BaseDAO` 的设计通常包含以下要点: 1. **泛型**: ...

    mysql多数据源连接代码

    JpaTransactionManager transactionManager = new JpaTransactionManager(); transactionManager.setEntityManagerFactory(entityManagerFactory1); return transactionManager; } @Bean(name = ...

    浅谈SpringBoot之事务处理机制

    例如,JPA事务使用JpaTransactionManager实现,JDBC事务使用DataSourceTransactionManager实现。 在程序中定义事务管理器的代码如下: @Bean public PlatformTransactionManager transactionManager() { Jpa...

    Spring事务配置的五种方式.doc

    Spring框架中事务配置是非常重要的一部分,通常由三个组成部分组成,即DataSource、TransactionManager和代理机制。无论采取何种配置方式,代理机制部分总是变化的,而DataSource和TransactionManager部分则根据数据...

    利用IDEA搭建的hibernate+Spring+SpringMVC架构实现增删改查等功能

    Spring配置文件则用于配置Spring的Bean,如DataSource、SessionFactory、TransactionManager以及SpringMVC的相关配置。 接下来,创建数据库模型(实体类),这些类将与数据库表进行映射。每个实体类对应一个数据库...

    Xml文件配置实现声明式事务管理

    本篇文章将深入探讨如何通过XML配置实现声明式事务管理。 首先,理解Spring中的事务管理概念是至关重要的。事务是一组操作,这些操作要么全部成功,要么全部失败,确保数据的一致性。在Java环境中,JDBC API提供了...

    springboot实现多数据源

    每个数据源都有自己的`DataSource`实例,可以是JDBC、Hibernate或MyBatis等。首先,我们需要在`application.properties`或`application.yml`中为每个数据源配置相关的连接信息,如URL、用户名、密码等。例如: ```...

    Android使用ORMLite进行数据库操作

    压缩包中的`ormliteDemo`项目是一个实际的示例,包含了上述所有概念的实现。通过查看和运行这个项目,你可以更好地理解ORMLite在Android中的具体用法。 总结,ORMLite为Android开发者提供了便捷的数据库操作方式,...

    基于JTA的跨数据库分布式事务的实现.pdf

    【基于JTA的跨数据库分布式事务的实现】 在大规模的企业级应用中,常常涉及到多个数据库系统的交互,这就需要实现跨数据库的分布式事务处理。Java Transaction API(JTA)是Java平台上的标准,用于管理和协调跨多个...

    aop方式实现数据库读写分离

    通常,每个数据源都有自己的`PlatformTransactionManager`实例。 5. **测试与验证**:编写单元测试或集成测试来确保读写分离功能正常工作,查看是否能正确地将读操作路由到读库,写操作路由到写库。 总结来说,...

    注解实现声明式事务管理

    在Spring框架中,注解是实现声明式事务管理的主要手段之一。相较于编程式事务管理,声明式事务管理更易于维护,因为事务管理的逻辑被声明在配置或元数据中,而不是散落在业务代码中。本篇文章将深入探讨如何使用注解...

    Spring Boot+Druid+Mybatis实现JTA分布式事务

    Mybatis则是一个轻量级的持久层框架,它简化了SQL操作,但在JTA事务中,Mybatis需要配合Spring的TransactionManager来工作,使得每个数据库操作都在同一个事务上下文中。 实现步骤如下: 1. 添加依赖:在Spring ...

    spring 事务配置

    本文详细介绍了Spring事务配置中的五种方式:基于XML的声明式事务管理、基于注解的声明式事务管理、编程式事务管理、通过AOP实现的事务管理以及通过代理模式实现的事务管理。每种方式都有其适用场景,开发者可以根据...

    spring + JTA + atomikos 实现分布式事务

    然后,Atomikos作为JTA的实现,提供了UserTransaction和TransactionManager的具体实现。UserTransaction接口允许应用程序开始、提交、回滚事务,而TransactionManager则负责事务的生命周期管理和资源协调。Atomikos...

Global site tag (gtag.js) - Google Analytics