HibernateX 實踐總結
Hibernate不是盞省油的燈也不是想像的射來射去很簡單的事有很多細節處理不好會讓你很不舒服的這方面最突出的表現在兩方面一是事務管理是JTA事務還是JDBC事務?幸虧有了Spring和JEE容器二是胡亂映射模型關系建立不合理或者錯誤導致或者是映射策略和技術不過關導致這樣的最終結果是拋出一堆HibernateException摸不著頭腦下面是我實踐中的一些總結作為備忘錄寫出來
參考的是最新的Hibernate GA API文檔還吸收了Hibernate牛人(夏新)寫的書和翻譯中文開發手冊的精華
Configuration/SessionFactory/Session
Configuration實例代表了一個應用程序中Java類型 到SQL數據庫映射的完整集合 Configuration被用來構建一個(不可變的 (immutable))SessionFactory
SessionFactory是線程安全的創建代價很高
Session是非線程安全的輕量級的一個Session對應一個JDBC連接
Session的connection()會獲取Session與之對應的數據庫連接Connection對象
Session的功能就是操作對象的這些對象和數據庫表有映射關系
Session操作的對象是有狀態的分三類
自由狀態(transient): 未持久化未與任何Session相關聯數據庫表中沒有對應的記錄
持久化狀態(persistent): 與一個Session相關聯對應數據庫表中一條記錄
游離狀態(detached): 已經進行過持久化但當前未與任何Session相關聯數據庫表中曾經有一條記錄現在還有沒有就不知道了
游離狀態的實例可以通過調用save()persist()或者saveOrUpdate()方法進行持久化持久化實例可以通過調用 delete()變成游離狀態通過get()或load()方法得到的實例都是持久化狀態的游離狀態的實例可以通過調用 update()saveOrUpdate()lock()或者replicate()進行持久化游離或者自由狀態下的實例可以通過調用merge()方法成為一個新的持久化實例
Session的save()/persist()/update()/saveOrUpdate()/merge()/delete()方法
save()方法將指定對象保存插入表中一條數據
persist()方法將指定對象保存插入表中一條數據我還沒發現它和save方法有什麼特別之處
replicate()方法完全使用給定對象各個屬性的值(包括標識id)來持久化給定的游離狀態(Transient)的實體很暴力啊其中還需要指定存儲模式(有四種保存策略供選擇)
update()方法將指定對象更新更新表中一條數據
saveOrUpdate()方法接收一個實體對象根據實體對象的id判斷是否已經存在進行保存或更新操作這樣保存和更新方法就統一了
merge()方法將給定的對象的狀態復制到具有相同標識的持久化對象上
delete()方法將指定對象刪除刪除表中一條數據
特別注意為了使用saveOrUpdate()方法在由定義映射文件時通過設定<id>標簽的unsavedvalue=null來判斷執行什麼操作 當id屬性等於unsavedvalue的值(在此為null)時則認為還沒有保存應該執行保存操作否則執行更新操作這樣設定之後可以使用saveOrUpdate()方法來統一保存和更新的方法
<id name=id column=id type=javalangInteger unsavedvalue=null>
<generator class=native/>
</id>
unsavedvalue可以設定的值有四個
any總是儲存
none總是更新
nullid為null時儲存(預設)
validid為null或是指定值時儲存
Session的get()/load()方法
get()方法會總是查詢實體對象不存在時候返回null
load()方法也是獲取一個實體對象不存在時候拋空指針異常
Session的clear()/evict()方法
clear()方法清除Session級別緩存中的所有實體(包括各種狀態)對象目的是釋放內存
evict()方法清除Session級別緩存中的指定的實體(包括各種狀態)對象
當然Session關閉後這些緩存也就不存在了會等待JVM回收
Session的flush()方法
flush()強制持久化Session緩存中的實體對象一般還會調用clear()或evict()目的是趕緊保存釋放寶貴內存資源
Session的commit()/rollback()方法
commit()方法用於提交Session上的事務否則工作單元不會對數據庫產生影響如果執行出現異常(也就是commit()失敗了)則之前的操作取消執行rollback()可撤消之前的操作
Session的close()/isOpen()/isConnected()/reconnect()方法
close()方法關閉Session所對應數據庫連接與其相關聯的對象生命周期結束
isOpen()方法檢查Session是否仍然打開如果Session已經斷開則可以使用reconnect(Connection connection)來重新讓Session關聯一個JDBC連接
isConnected()方法檢查當前Session是否處於連接狀態
CriteriaDetchedCriteria和Query接口
Criteria和Query的實例都是和Session綁定的其生命周期跟隨著Session結束而結束
DetchedCriteria實例相當於一個SQL模板目的是為了復用其中的getExecutableCriteria(session)方法接收一個Session對象並與之綁定返回一個Criteria對象
Hibernate類的initialize()方法
initialize()方法強制Hibernate立即加載指定實體所關聯的對象和集合Hibernate類中還有其他幾個很有用但不適很常用的方法
映射文件中的lazy屬性
在Hibernate中class元素的lazy屬性默認是true如果不需要則需要顯示指定為lazy=false否則操作load返回的對象會拋異常另外Hibernate中還可以為實體屬性指定lazy屬性
JDBC事務和JTA事務
Hibernate本身沒有事務管理功能它依賴於JDBC或JTA的事務管理功能在Hibernate配置文件中如果不顯式指定Transaction的工廠類別屬性hibernatetransactionfactory_class的配置則默認為JDBC事務
<property name=hibernatetransactionfactory_class>orghibernatetransactionJDBCTransactionFactory</property>
在通過SessionFactory獲取到Session後與Session相關聯的JDBC Connection實例就被設定為false
特別注意如果數據庫不支持事務比如MySQL的MyISAM引擎的表就不支持事務聲明事務也不會起作用要使MySQL的表支持事務則可以指定表的引擎類型為InnoDB如果是學習或者研究目前最好還是使用PostgreSQL 或DBOracle
JDBC事務總是和一個數據庫連接(或一個Session)相關聯的
JTA事務則可以跨越多個數據連接(或多個Session)這些連接還可以是不同數據庫的連接JTA事務一般由容器進行管理編程只要在多個操作單元的開始和結束定義JTA事務的邊界即可
特別注意如果使用了JTA事務則不能再用在JDBC式的事務來管理每個Session的操作否則會出錯為了程序的的通用性一般來說都是使用JTA事務來構建應用這使用任何環境當然也可以使用事務代理為每個JDBC的操作方法加入事務控制這樣也為程序以後移植到JTA容器事務上帶來很大方便其實現在可以使用Spring的事務管理與Hibernate結合的非常完美
From:http://tw.wingwit.com/Article/program/Java/ky/201311/28559.html