论坛首页 Java企业应用论坛

自己实现的TransactionManager

浏览 5888 次
精华帖 (0) :: 良好帖 (0) :: 新手帖 (0) :: 隐藏帖 (0)
作者 正文
   发表时间:2007-02-23  
背景:
目前有一个系统,系统已经写好了,但是要不停的添加新的功能,用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);
	}
}
   发表时间: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这两个异常.
0 请登录后投票
   发表时间: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再绑一次?
0 请登录后投票
   发表时间:2007-02-27  
to JAVA_ED:

什么意思,能否详细说明一下?
不new ConnectionHolder()那用同一个ConnectionHolder?
0 请登录后投票
   发表时间:2007-02-27  
jamesby 写道
to JAVA_ED:

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


nested transaction? 所谓ConnectionHolder应该是个Connection Container
如果每次begin都去新开个connection, 那前一次的不是丢失了吗
这样不如把connection直接绑上去
0 请登录后投票
   发表时间: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的.

0 请登录后投票
   发表时间: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如何实现

0 请登录后投票
   发表时间: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类的东西先跑起来.
0 请登录后投票
   发表时间:2007-04-09  
正在做毕业设计,不想引入Spring,时间不够,学不过来。
就借用下!!

PS:我会保留版权信息的!呵呵!
0 请登录后投票
   发表时间:2007-04-12  
有个问题,在end的同时,是否应该ThreadLocal.remove()呢?
0 请登录后投票
论坛首页 Java企业应用版

跳转论坛:
Global site tag (gtag.js) - Google Analytics