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詳解