Session 是 Java 應用與 Hibernate 框架交互的核心介面,提供映射實體類實例的增刪改查操作。每個實例處於三種狀態之一:
| 來源狀態 | 目標狀態 | 方法 | SQL |
|---|---|---|---|
| Transient | Persistent | save()、persist()、saveOrUpdate() | INSERT |
| Persistent | Transient | delete() | DELETE |
| Persistent | — | 修改屬性 → flush() | UPDATE |
| Detached | Persistent | update()、saveOrUpdate()、lock()、replicate() | UPDATE/INSERT |
| Transient/Detached | Persistent (新物件) | merge() | INSERT/UPDATE |
關鍵差異:merge() 會複製屬性到新建的持久化物件,原物件不變;saveOrUpdate() 則嘗試重用原物件。
Session 實作類非線程安全,每個線程/事務必須從 SessionFactory 獲取獨立實例。
Session sess = factory.openSession();
Transaction tx = null;
try {
tx = sess.beginTransaction();
// 業務操作...
tx.commit();
} catch (Exception e) {
if (tx != null) tx.rollback();
throw e;
} finally {
sess.close();
}
若 Session 拋出異常,事務必須回滾,且 Session 需丟棄(內部狀態可能與資料庫不一致)。
@Test
public void testSave() {
User user = new User();
user.setBirthday(new java.sql.Date(0));
user.setName("binyulan");
// native 策略,MySQL 自增主鍵,無需設定 id
Serializable id = session.save(user); // 回傳生成的主鍵
}
@Test
public void testPersist() {
User user = new User();
user.setBirthday(new java.sql.Date(0));
user.setName("binyulan");
user.setId(13); // 若設定 id 會拋出 PersistentObjectException
session.persist(user); // 無回傳值
}
異常提示 detached entity passed to persist,推測:只要設定了 id,Hibernate 視為遊離態,即使未持久化過。
// 情況 A:無 id → INSERT,回傳新持久化物件
User user = new User(); user.setName("binyulan2");
User user1 = (User) session.merge(user);
System.out.println(user1 == user); // false,user 不在 Session 中
// 情況 B:有 id → 先 SELECT,再 UPDATE 或 INSERT
user.setId(20L); // 假設 DB 有 id=20
User user2 = (User) session.merge(user); // UPDATE
user.setId(123456789L); // DB 無此 id
User user3 = (User) session.merge(user); // INSERT
merge() 總是回傳新建的持久化物件,原物件保持瞬時/遊離態。
更多方法(load()、get()、update()、delete()、lock()、refresh()、evict()、clear()、flush())及最佳實踐,敬請關注後續章節。