利用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 [email protected]

 * @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();

	}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章