public class HibernateTestBean implements SessionBean {
SessionContext sessionContext;
SessionFactory sf;
public void setSessionContext(SessionContext sessionContext) {
this.sessionContext = sessionContext;
try {
InitialContext ctx = new InitialContext();
sf = (SessionFactory) ctx.lookup("java:/hibernate/SessionFactory");
} catch (NamingException ex) { ex.printStackTrace(); }
}
public void tran() { tran1(); tran2(); }
public void tran1() {
Session session = sf.getCurrentSession();
Message msg = new Message();
msg.setCreateTime(new Date());
msg.setDetail("trans1");
session.save(msg);
System.out.println("Session:" + session.hashCode());
session.flush();
session.close(); // 錯誤!
}
public void tran2() {
Session session = sf.getCurrentSession(); // 將拋出異常
Message msg = new Message();
msg.setCreateTime(new Date());
msg.setDetail("trans2");
session.save(msg);
System.out.println("Session:" + session.hashCode());
// throw new RuntimeException("wrong");
}
}
假設:EJB 採用 CMT,所有方法事務屬性為 Required。
sf.getCurrentSession() 返回當前事務上下文綁定的 Session (即 ThreadLocal 模式)session.close() 導致 Session 提前關閉,但事務尚未結束getCurrentSession() 時容器嘗試返回同一 Session,發現已關閉 → 拋出異常原則:使用 getCurrentSession() 時,Session 由容器自動管理,開發者不可呼叫 close()、flush() (CMT 下 flush 也通常不需手動)。事務完成時容器自動 flush 並 close。
openSession() 每次創建新 Session,不綁定事務上下文getCurrentSession() 取得容器管理的 Session,正常運作| 場景 | 建議 |
|---|---|
| CMT 環境,需容器管理事務 | 全程使用 sf.getCurrentSession(),絕不手動 close/flush |
| 需手動控制 Session 生命週期 (BMT 或特殊需求) | 使用 sf.openSession(),自行管理 begin/commit/rollback/close |
| 長會話 (Long Conversation) | 考慮 Hibernate 手動斷開/重新連接機制或 Spring OpenSessionInView |
getCurrentSession() = 事務綁定 Session,容器負責開關;
openSession() = 手動 Session,自己負責開關。
CMT 下混用會導致事務邊界混亂,資料一致性風險極高。