利用ThreadLocal绑定Hibernate的session

前几天在csdn论坛里面,经常有人问到,如果不用spring,单用hibernate如何来解决延迟加载的问题.

无论是立即加载还是延迟加载必须要连接数据库的,而在java中连接数据库是依赖java.sql.Connection,在hibernate中session就是Connection的一层高级封装,一个session对应了一个Connection,要实现延迟加载必须有session才行.而且要进行延迟加载还必须保证是同一个session才行,用另外一个session去延迟加载前一个session的代理对象是不行的.大家都知道Connection是使用过后必须要进行关闭的,那么我们如何保证一次http请求过程中,一直都使用一个session呢,即一个Connection呢.而且还要保证http请求结束后正确的关闭.

好,现在我们知道了我们要解决的问题

1.如何保证http请求结束后正确的关闭session

2.如何保证http请求过程中一直使用同一个session

第一个问题很容易想到,使用过滤器

	public void doFilter(ServletRequest request, ServletResponse response,

			FilterChain filterChain) {

		try {

			filterChain.doFilter(request, response);

		} catch (IOException e) {

			e.printStackTrace();

		} catch (ServletException e) {

			e.printStackTrace();

		} finally {

			try {

				HibernateUtil.commitTransaction();

			} catch (Exception e) {

				HibernateUtil.rollbackTransaction();

			} finally {

				HibernateUtil.closeSession();

			}

		}

	}

要解决第二个问题我们必须先搞清楚,http请求在java中是以什么样的机制实现的,在java中一个请求就是一个线程,像流行的web容器Tomcat等,往往都是采用线程池机制的也就是说有n个线程在池子里面,每当有http请求时,随机从线程池中取出一个线程对象去处理请求,实际上多次请求可能使用的是同一线程也可能不是,这是随机的.要保证整个请求中使用同一session最容易想到的就是把这个session绑定到线程上,在java中使用ThreadLocal可以轻松绑定变量,每个线程有一个自己的ThreadLocal,这个ThreadLocal会随线程的销毁一起销毁,既然是每个线程有一个那么多个线程间自然是不会有影响了,所以把session绑定在ThreadLocal里面是最好的选择了,

有关ThreadLocal的更多资料,大家可以百度或者参考

http://www-128.ibm.com/developerworks/cn/java/j-threads/index3.html

http://www.blogjava.net/jspark/archive/2006/08/01/61165.html

最后我把相关的代码发出来

import java.sql.SQLException;

import org.hibernate.HibernateException;

import org.hibernate.Session;

import org.hibernate.SessionFactory;

import org.hibernate.Transaction;

import org.hibernate.cfg.Configuration;

import java.sql.Connection;

import org.apache.log4j.Logger;

import java.io.File;



/**

 * 

 * <p>

 * Title:Hibernate工具类

 * </p>

 * 

 * <p>

 * 利用ThreadLocal 绑定 Hibernate 的session

 * </p>

 * 

 * @author 孙钰佳 

 * @mail sunyujia@yahoo.cn

 * @version 1.0

 */

public class HibernateUtil {

	/**

	 * Loger4j的logger

	 */

	private static final Logger logger = Logger.getLogger(HibernateUtil.class);

	/**

	 * 存储hibernate session的ThreadLocal

	 */

	private static final ThreadLocal sessionThread = new ThreadLocal();

	/**

	 * 存储事务的ThreadLocal

	 */

	private static final ThreadLocal transactionThread = new ThreadLocal();

	/**

	 * Hibernate 的 Session工厂

	 */

	private static SessionFactory sessionFactory = null;



	/**

	 * 初始化SessionFactory

	 * 

	 * @param file

	 *            Hibernate配置文件

	 */

	public static void initSessionFactory(File file) {

		Configuration config = new Configuration();

		config.configure(file);

		sessionFactory = config.buildSessionFactory();

	}



	/**

	 * 获取当前线程绑定的session

	 * 

	 * @return Session

	 * @throws HibernateException

	 */

	public static Session getSession() {

		Session s = (Session) sessionThread.get();

		if (s == null) {

			s = sessionFactory.openSession();

			sessionThread.set(s);

		} else {

			Connection conn = s.connection();

			try {

				if (conn == null || conn.isClosed()) {

					try {

						s.close();

					} catch (HibernateException e) {

						logger.warn("close session error:" + e.getMessage(), e);

					}

					s = sessionFactory.openSession();

					sessionThread.set(s);

				}

			} catch (SQLException e) {

				throw new HibernateException(e);

			}

		}

		return s;

	}



	/**

	 * 取得当前session的事务

	 * 

	 * @return Transaction

	 */

	public static Transaction transaction() {

		Transaction transaction = (Transaction) transactionThread.get();

		if (transaction == null) {

			transaction = getSession().beginTransaction();

			transactionThread.set(transaction);

		}

		return transaction;

	}



	/**

	 * 提交当前session的事务

	 */

	public static void commitTransaction() {

		Transaction transaction = (Transaction) transactionThread.get();

		transactionThread.set(null);

		if (transaction != null)

			transaction.commit();

	}



	/**

	 * 回滚当前session的事务

	 */

	public static void rollbackTransaction() {

		Transaction tx = (Transaction) transactionThread.get();

		transactionThread.set(null);

		if (tx != null)

			tx.rollback();

	}



	/**

	 * 关闭当前线程使用的session

	 */

	public static void closeSession() {

		Session session = (Session) sessionThread.get();

		if (session != null) {

			session.clear();

			session.close();

			sessionThread.set(null);

		}

	}

}

 

下面是一个调用的例子:
	public static void main(String[] args) throws Exception {

		HibernateUtil.initSessionFactory(new File(Test.class.getClassLoader()

				.getResource("hibernate.cfg.xml").getFile()));

		Session session = HibernateUtil.getSession();

		HibernateUtil.transaction();

		User u = new User();

		u.setName("test");

		session.save(u);

		HibernateUtil.commitTransaction();

		HibernateUtil.closeSession();

	}
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值