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。

參考:http://www.xuebuyuan.com/1587708.html


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)了。

詳情請參考:Hibernate Session & Transaction詳解





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