1. 程式人生 > >connection、HttpSession、hibernate中的session、transaction

connection、HttpSession、hibernate中的session、transaction

connection和HttpSession的區別

session(會話)和connection(連線)的定義:
connection
:是一個物理的概念,它指的是一個通過網路建立的客戶端和專有伺服器(Dedicated Server)或共享伺服器(Shared Server)的一個網路連線,既是一條物理路勁。

session:是一個邏輯的概念,它是存在於例項中,一個連線可以擁有多個會話也可以沒有會話,同一個連線上的不同會話之間不會相互影響。

有A/B兩個城市,需要從A運送白菜到B城 


我們先建設一條公路 
然後運送白菜過去,包括準備白菜和運送白菜以及返回等一系列的動作。 

一條公路,可以運送0-n次的白菜 

當然從A到B的公路也可能不只一條。 
某一次運送白菜,可以在真正上路時才開通某一條道路 
一次運送不會影響別的運送的狀態 


對應資料庫 
A代表客戶端程序 
B代表伺服器端程序 
公路代表連線, 
運送一次白菜代表一個會話 

一個連線可以進行多次的會話 
一個會話可以不依賴於某個連線,甚至沒有連線(當我準備好了,真正開始運送時再建立連線) 

一個會話不會影響別的會話

ThreadLocalSessionContext的名稱上看,它所做的就是把一個session繫結到當前執行緒上,讓當前執行緒作為session的上下文。這樣,在service裡不同的dao通過sessionFactory.getCurrentSession()得到的將是當前執行緒上的同一個session,這是非常必要的做法,通過使用同一個session確保了持久化物件的一致性。但是從

ThreadLocalSessionContext的程式碼來看,它並只是做了這一件事,它還做了另外一件非常“醒目”的事情:即給session包裹了一層代理org.hibernate.context.ThreadLocalSessionContext$TransactionProtectionWrapper,這個代理將攔截session的操作,對session的使用做出瞭如下的限制:

1.在沒有顯式地開始一個事務之前,不能使用session的任何資料訪問方法。

2.一旦事務提交,session將自動close。

Session是JAVA應用程式和Hibernate進行互動時使用的主要介面,它也是持久化操作核心API,

Session物件是有生命週期的,它以Transaction物件的事務開始和結束邊界 。Session作為貫穿Hibernate的持久化管理器核心,提供了眾多的持久化的方法,如save(), update ,delete ,find(Hibernate 3中已經取消了此方法)等,通過這些方法我們可以透明的完成物件的增刪改查。

SessionFactory負責建立Session,SessionFactory是執行緒安全的,多個併發執行緒可以同時訪問一個SessionFactory 並從中獲取Session例項。而Session並非執行緒安全,也就是說,如果多個執行緒同時使用一個Session例項進行資料存取,則將會導致Session 資料存取邏輯混亂.因此建立的Session例項必須在本地存取空上執行,使之總與當前的執行緒相關。 Session有以下的特點   1,不是執行緒安全的,應該避免多個執行緒共享同一個Session例項    2,Session例項是輕量級的,所謂輕量級:是指他的建立和刪除不需要消耗太多資源    3,Session物件內部有一個快取,被稱為Hibernate第一快取,他存放被當前工作單元中載入的物件,每個Session例項都有自己的快取。 Hibernate Session快取被稱為Hibernate的第一級快取。SessionFactory的外接快取稱為Hibernate的二級快取。 這兩個快取都位於持久層,它們存放的都是資料庫資料的拷貝。SessionFactory的內建快取存放元資料和預定義SQL, SessionFactory的內建快取是隻讀快取。 Hibernate Session快取的三大作用 1,減少資料庫的訪問頻率,提高訪問效能。 2,保證快取中的物件與資料庫同步,位於快取中的物件稱為持久化物件。 3,當持久化物件之間存在關聯時,Session 保證不出現物件圖的死鎖。 Session 如何判斷持久化物件的狀態的改變呢? Session 載入物件後會為物件值型別的屬性複製一份快照。當Session 清理快取時,比較當前物件和它的快照就可以知道那些屬性發生了變化。 Session 什麼時候清理快取? 1,commit() 方法被呼叫時 2,查詢時會清理快取,保證查詢結果能反映物件的最新狀態。 3,顯示的呼叫session 的 flush方法。 session 清理快取的特例: 當物件使用 native 生成器時會立刻清理快取向資料庫中插入記錄。
public class HibernateUtil {

	public static final SessionFactory sessionFactory;
	public static final ThreadLocal<Session> session = new ThreadLocal<Session>();
	static {
		try {
			Configuration configuration = new Configuration().configure();
			sessionFactory = configuration.buildSessionFactory();
		} catch (Throwable ex) {
			System.err.println("Initial SessionFactory creation failed." + ex);
			throw new ExceptionInInitializerError(ex);
		}
	}

	public static Session currentSession() throws HibernateException {
		Session s = (Session) session.get();
		if (s == null) {
			s = sessionFactory.openSession();
			session.set(s);
		}
		return s;
	}

	public static void closeSession() throws HibernateException {
		Session s = (Session) session.get();
		if (s != null)
			s.close();
		session.set(null);
	}
}


通過以上程式碼(ThreadLocal<Session>),我們就可以實現執行緒範圍內的Session共享,從而避免了線上程中頻繁的建立和銷燬Session 例項。不過注意線上程結束時關閉Session。同時值得一提的是,新版本的Hibernate在處理Session的時候已經內建了延遲載入機制,只有在真正發生資料庫操作的時候,才會從資料庫連線池獲取資料庫連線,我們不必過於擔心Session的共享會導致整個執行緒生命週期內資料庫
Hibernate Transaction是從Session中獲得的,tx = session.beginTransaction(),最後要先提交tx,然後再session.close,這完全符合JDBC的Transaction的操作順序,但是這個順序是和JTA的Transactioin操作順序徹底矛盾的!!! JTA是先啟動Transaction,然後啟動Session,關閉Session,最後提交Transaction,因此當你使用JTA的Transaction的時候,那麼就千萬不要使用Hibernate的Transaction
總結:  1、在JDBC上使用Hibernate  必須寫上Hibernate Transaction程式碼,否則資料庫沒有反應。此時Hibernate的Transaction就是Connection.commit而已  2、在JTA上使用Hibernate  寫JTA的Transaction程式碼,不要寫Hibernate的Transaction程式碼,否則程式會報錯  3、在EJB上使用Hibernate  什麼Transactioin程式碼都不要寫,在EJB的部署描述符裡面配置  Java程式碼   |---CMT(Container Managed Transaction);    |    |---BMT(Bean Managed Transaction);            |            |----JDBC Transaction            |            |----JTA Transaction    你說“Hibernate的JDBCTransaction根本就是conn.commit而已,根本毫無神祕可言,只不過在Hibernate中,Session開啟的時候,就會自動conn.setAutoCommit(false),不像一般的JDBC,預設都是true,所以你最後不寫commit也沒有關係,由於Hibernate已經把AutoCommit給關掉了,所以用Hibernate的時候,你在程式中不寫Transaction的話,資料庫根本就沒有反應”  但sf.opengSession()時,並沒有setAutoCommit(false),我想問的是,如果不編寫任何事務程式碼,如:  Java程式碼   Session s = sf.openSession();;    ......    s.close();;   資料庫會不會有反應(此時應該是預設AutoCommit為true)。  另外,我想問一下:  1. s.flush()是不是必須的  2. s.close()是不是一定要關閉  比如你上面提到的:  Java程式碼   javax.transaction.UserTransaction tx = new InitialContext();.lookup("javax.transaction.UserTransaction");;     Session s1 = sf.openSession();;     ...     s1.flush();;     s1.close();;     .. Session s2 = sf.openSession();;     ...     s2.flush();;     s2.close();;     tx.commit();;   s1不關閉,使用s2進行操作的程式碼中使用s1可不可以(我覺得這樣更加節約資源,不需要反覆的連線、關閉) 引用 但sf.opengSession()時,並沒有setAutoCommit(false),我想問的是,如果不編寫任何事務程式碼,如:  Session s = sf.openSession();  ......  s.close();  資料庫會不會有反應(此時應該是預設AutoCommit為true)。 不會有反應。在sf.openSession() 建立Session例項的時候,就已經呼叫了conn.setAutoCommit(false)了。