论坛首页 Java企业应用论坛

在B/S应用中用ThreadLocal管理Connection是否可取

浏览 15819 次
精华帖 (0) :: 良好帖 (0) :: 新手帖 (0) :: 隐藏帖 (0)
作者 正文
   发表时间:2004-04-20  
用ThreadLocal可以解决一定的事务问题
但在Web应用中,我发现在filter里面close连接无疑是最合适的

如果在其他地方close 连接,后面的调用得到的connection就是isColsed,无法再使用,如果再open一次,就不是以前的连接了,就无法保证事务了

并且用ThreadLocal实现的也只是粗粒度的事务,尤其是在B/S应用中

ThreadLocal,鸡肋? 
   发表时间:2004-04-20  
ejb中的container managered transaction用的也是类似ThreadLocal或者就是ThreadLocal的技术,ejb也是鸡肋
还是好好看看ThreadLocal到底是个什么东东吧?
0 请登录后投票
   发表时间:2004-04-20  
为什么说threadlocal是鸡肋呢?关键是看你如何设计吧。我觉得使用threadlocal和使用filter在web 里面效果是一样的,而threadlocal更通用一点,可以用在非web的场合。
0 请登录后投票
   发表时间:2004-04-20  
sorry

我想我已经理解ThreadLocal是什么了

直接说ThreadLocal是鸡肋的确不对
现在把问题定位在“在B/S应用中用ThreadLocal管理Connection是否可取”上

我觉得这并不是一个很好的方法,原因同上
0 请登录后投票
   发表时间:2004-04-20  
wes109 写道
用ThreadLocal可以解决一定的事务问题
但在Web应用中,我发现在filter里面close连接无疑是最合适的

如果在其他地方close 连接,后面的调用得到的connection就是isColsed,无法再使用,如果再open一次,就不是以前的连接了,就无法保证事务了

并且用ThreadLocal实现的也只是粗粒度的事务,尤其是在B/S应用中

ThreadLocal,鸡肋? 


你为什么要在其他地方close呢?

事务的scope是在Session的scope里面的,你都已经close了Session了,当然不会在一个事务里面了。

你怎么知道是粗粒度,那是你不会用,你就不会把Transaction也放到ThreadLocal里面,实现细粒度的事务控制吗?贴段代码给你参考:

/*
 * Created on 2003-11-16
 *
 */
package com.javaeye.crm;

import net.sf.hibernate.HibernateException;
import net.sf.hibernate.Session;
import net.sf.hibernate.SessionFactory;
import net.sf.hibernate.Transaction;
import net.sf.hibernate.cfg.Configuration;
import net.sf.hibernate.tool.hbm2ddl.SchemaExport;

/**
 * 
 * 获取Session连接工厂类
 * 
 * @author Robbin Fan
 *
 */
public class HibernateSession {	
	
	private static final ThreadLocal sessionThread = new ThreadLocal();;
	
	private static final ThreadLocal transactionThread = new ThreadLocal();;
	
	private static SessionFactory sf = null;
	
	/**
	 * 获取当前线程使用的Session
	 * 
	 * @return Session
	 * @throws HibernateException
	 */
	public static Session currentSession(); throws HibernateException {	
		Session s = (Session); sessionThread.get();;		
		if (s == null); {
			if (sf == null); sf = new Configuration();.configure();.buildSessionFactory();;	
			s = sf.openSession();;
			sessionThread.set(s);;		
		}
		return s;
	}

	/**
	 * 获取一个新的Session
	 * 
	 * @return Session
	 * @throws HibernateException
	 */
	public static Session newSession(); throws HibernateException {	
	
		if (sf == null); sf = new Configuration();.configure();.buildSessionFactory();;	
		Session s = sf.openSession();;
		return s;
	}
		
	/**
	 * 启动或者加入当前Session的Transaction
	 * 
	 * @return Transaction
	 * @throws HibernateException
	 */
	public static Transaction currentTransaction(); throws HibernateException {
		Transaction tx = (Transaction); transactionThread.get();;
		if (tx == null); {
			tx = currentSession();.beginTransaction();;
			transactionThread.set(tx);;
		}
		return tx;
	}
	
	/**
	 * 提交当前Session的Transaction
	 * 
	 * @throws HibernateException
	 */
	public static void commitTransaction(); throws HibernateException {
		Transaction tx = (Transaction); transactionThread.get();;
		transactionThread.set(null);;
		if (tx != null); tx.commit();;
	}

	/**
	 * 回滚当前事务
	 * 
	 * @throws HibernateException
	 */
	public static void rollbackTransaction(); throws HibernateException {
		Transaction tx = (Transaction); transactionThread.get();;
		transactionThread.set(null);;
		if (tx != null); tx.rollback();;
	}
		
	/**
	 * 关闭当前线程使用的Session
	 * 
	 * @throws HibernateException
	 */
	public static void closeSession(); throws HibernateException {			
		Session s = (Session); sessionThread.get();;		
		sessionThread.set(null);;
		if (s != null); s.close();;
	}

	/**
	 * 根据映射文件和持久对象生成数据库DDL,生成文件为create_table.sql
	 * 
	 * @param args 参数
	 */
	public static void main(String[] args); {
		try {
			String conf = "hibernate.cfg.xml";
			if (args.length != 0); conf = args[0];
			Configuration cfg = new Configuration();.configure("/" + conf);;
			SchemaExport se = new SchemaExport(cfg);;
			//se.setOutputFile("create_table.sql");;
			se.create(true,true);;
		} catch (HibernateException e); {			
			System.out.println(e.getMessage(););;
		}
		
	}
}


在你的DAOImpl中,你直接:

Session session = HibernateSession.currentSession();;
HibernateSession.currentTransaction();;
.....
session.flush();;

事务的提交和Session的close都在Filter里面完成,Filter里面代码如下:

		try {
			HibernateSession.commitTransaction();;
		} catch (HibernateException e); {		
			try {
				HibernateSession.rollbackTransaction();;
			} catch (HibernateException e1); {
				System.out.println(e1.getMessage(););;
			}	
			System.out.println(e.getMessage(););;
		} finally {
			try {
				HibernateSession.closeSession();;
			} catch (HibernateException e); {
				System.out.println(e.getMessage(););;
			}
		}


这是粗颗粒度的Transaction。

如果该DAO需要一个细颗粒度的事务的话,那么你就

Session session = HibernateSession.currentSession();;
HibernateSession.currentTransaction();;
.....
session.flush();;
HibernateSession.commitTransaction();;

这样就可以实现一个细颗粒度的事务,而且在该线程执行序列中,接下去的另一个方法调用也是类似:

Session session = HibernateSession.currentSession();;
HibernateSession.currentTransaction();;
.....
session.flush();;

这样的代码,而HibernateSession.currentTransaction();会自己检查当前是否已经启动事务,如果发现没有启动事务,那么就会新启动一个事务的。

因此,如果你需要细颗粒度的事务的话,就在你方法里面
HibernateSession.commitTransaction();;
如果你不需要细颗粒度事务的话,就不写这句代码就OK了,最后Filter会提交。
0 请登录后投票
   发表时间:2004-04-20  
妙!!!
0 请登录后投票
   发表时间:2004-04-20  
前天看hibernate的source,一直没弄明白session和transaction是怎么关联的
Session.java有30多K,看得头晕:(

其实我想参照hibernate的代码,实现自己的Connection和Transaction管理,呵呵

可能没有必要,只是想做一个尝试,了解一个实现机制

偶是菜鸟,见笑了

robbin能写一些hibernate源码剖析的文章就好了。。。
0 请登录后投票
   发表时间:2004-04-20  
你太客气了,有空再说吧,最近忙死了。
0 请登录后投票
   发表时间:2004-04-20  
突然想到:

在filter里面操作session和transaction是否与各层分离的思想不符?    
0 请登录后投票
   发表时间:2004-04-21  
wes109 写道
突然想到:

在filter里面操作session和transaction是否与各层分离的思想不符?    


你不一定非要在filter里面操作不可,准确的来说,只不过是需要在一个层的边界来操作,例如你如果分离Web层和业务层的话,你可以在业务层的Session Facade来完成这个工作,前提是你要保证在每个方法最后都close一下Session。
0 请登录后投票
论坛首页 Java企业应用版

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