J2EE持久層持久化上下文的傳播以及會話(Conversation)實現
目前持久層框架都有一個持久化上下文的概念,下面以比較流行的hibernate以及JPA來做一總結。
如果我們採用OO的方式開發系統,那麼勢必為了減低耦合,增加內聚,我們會通過細粒度的類來實現業務功能,那麼這樣就產生了一個問題,如何將持久化上下文在不同的類(這裡面其實就是Dao類或者DDD裡面的repository)中傳播,比如傳統的開發方式中,一個service裡通過不同的Dao來訪問資料庫,那麼怎麼保證不同的Dao類中用的session以及以及與session對應的持久化上下文是同一個呢?這就涉及到了持久化上下文如何傳播的問題。下面以我熟悉的hibernate以及JPA來來說明一下,在hibernate中,根據採用的底層事務的不同,需要採用不同的策略來實現:
1 Hibernate中持久化上下文的傳播
1.1 採用jdbc事務
此時hibernate通過Threadlocal將當前的session與當前的執行緒繫結在一起,這樣以來只要是同一個執行緒中的呼叫,那麼獲得的session都是同一個,具體來說就是配置hibernate.current_session_context_class屬性為thread,這樣以來hibernate內部就會通過CurrentSessionContext介面的實現類ThreadlocalSessionContext通過threadlocal來將session和當前執行緒繫結在一起。當呼叫SessionFactory的getCurrentSession()方法,返回的就是與當前執行緒繫結的session,從而解決了持久層上下文傳播的問題。
1.2 採用JTA事務
此時hibernate內部是將當前的session以及對應的持久化上下文繫結到了全域性的JTA事務上,這樣以來我們通過sessionFactory的getCurrentSession()方法獲得的就是與當前的JTA事務繫結的session.具體一點就是配置屬性hibernate.current_session_context_class為jta,這樣以來hibernate內部就是通過CurrentSessionContext介面的實現類JTASessionContext來將session與當前的JTA全域性事務繫結在一起,因此當我們通過sf.getCurrentSessionContext()來獲取session時,獲得的就是與當前的JTA繫結到一起的session.
但是在此種情況下,需要特別注意一個問題:不能同時使用hibernate的Transaction介面與getCurrentSession(),因為當前的session是繫結到全域性JTA事務中的,如果通過session.beginTransaction()來開始事務,這說明以前沒有事務,既然沒有事務存在,我們的session又是怎麼繫結到全域性JTA事務上的呢?所以一定要注意:當使用JTA事務,並且用了getCurrentSession()的方法時,一定不要用hiernate的native transaction 介面。但是我們如果我們用openSession(),那麼就可以通過通過hibernate的native Transaction介面來控制JTA事務。
最後還需要弄清楚一點,Hibernate中還有一種繫結持久化上下文的方法,那就是通過設定hibernate.current_session_context_class屬性為managed,hiberante內部就是通過CurrentSessionContext介面的實現類ManagedSessionContext來繫結的。在此種情況下主要是為了實現會話,會話在hibernate中的實現介紹。
2 JPA中持久化上下文的傳播
JPA中持久化上下文的傳播根據採用不同的事務模型而不同,下面分別來說明:
2.1 採用resource-local事務模型
如果採用resource-local事務模型,此種情況也就是在非J2EE應用伺服器的支援下使用。那麼我們的持久化上下文的生命週期是與當前的EntityManager繫結到一起的,所以我們可以在不同的類中傳播相同的EntityManager例項來達到傳播事務上下文的傳播。
2.2 採用JTA事務模型
在此種模型下面,我們有EJB容器的支援,持久化上下文的傳播是藉助於事務上下文來傳播的,在說明如何傳播前首先要明確EJB元件中兩種不同的事務上下文的生命週期:
對於stateless session bean,持久化上下文的生命週期是與當前的系統事務一致的,這也就是無狀態會話bean的事務型的持久化上下文,每當事務結束,持久化上下文也就結束了,所有持久化物件也就變為了脫管的(detached).
對於statefull session bean,持久化上下文的生命週期是與當前的有狀態會話bean一致的,只有當有狀態的會話bean從系統中移除的時候,持久化上下文才關閉,這也就是有狀態會話bean的擴充套件的事務上下文。
搞清楚了這兩種不同的事務上下文的生命週期以後,我們來說一下持久化上下文如何傳播的問題。持久化上下文是通過當前系統事務來傳播的,當一個EJB元件呼叫另一個EJB元件的時候,如果兩個EJB元件的事務範圍是一樣的,那麼持久化上下文就會傳播,下面分幾種情況來說明:
無狀態會話bean之間呼叫:此時如果兩個無狀態會話bean在同一個事務中呼叫,那麼持久化上下文就是同一個,通過當前事務來傳播。
有狀態會話bean呼叫無狀態會話bean:此種情況下如果兩者在同一個事務中,那麼有狀態會話bean的擴充套件的事務上下文會傳播到無狀態會話bean裡,其實還是通過事務來傳播。但是如果被呼叫的無狀態會話bean不支援事務的話(事務屬性設定為not support 或者never),那麼此時持久化上下文不能傳播(JPA規範規定擴充套件的持久化上下文是不能傳播到無事務的stateless session bean)。
有狀態會話bean之間呼叫:此時無論兩個有狀態會話bean是否支援事務,那麼擴充套件的持久化上下文都會傳播,此時就不是通過系統事務來傳播的,而是通過statefull session bean的例項來傳播(但是此時一定要注意有狀態會話bean必須是通過容器注入的或者顯示通過JNDI查詢)。
無狀態的會話bean呼叫有狀態會話bean:一個有事務範圍的持久化上下文的stateless session bean呼叫一個statefull session bean會引發一個錯誤,因為當前的事務上下文不能傳播)
綜上所述,EJB之間的持久化上下文傳播是通過我們的系統事務來傳播的,如果EJB不支援事務(事務屬性設定為not support或者never)),那麼持久化上下文就不會傳播,但是對於擴充套件的持久化上下文,是通過statefull session bean來傳播的,即使沒有事務也可以傳播。
前面說的是關於持久化如何在持久層的不同的類之間傳播的問題,其實無外乎就是通過當前的執行緒和當前的系統事務來傳播,不過對與statefull session bean的擴充套件的持久化上下文,傳播是通過例項來傳播的,在下面的實現會話的討論中,我還會說到這個問題。當我們掌握了原理的時候,遇到一些問題的時候,我們就會很快找到解決方案。
[該貼被admin於2008-12-18 09:47修改過]
相關文章
- 使用Spring Data JPA實現持久化層的簡化開發Spring持久化
- 擴充套件的持久化上下文問題套件持久化
- Redis資料持久化—RDB持久化與AOF持久化Redis持久化
- Redis的兩種持久化方式-快照持久化(RDB)和AOF持久化Redis持久化
- MQTT 持久會話與 Clean Session 詳解MQQT會話Session
- Redis學習 RDB和AOF兩種持久化介紹以及實現Redis持久化
- GO實現Redis:GO實現Redis的AOF持久化(4)GoRedis持久化
- Redis 設計與實現 (三)--持久化Redis持久化
- redis系列:RDB持久化與AOF持久化Redis持久化
- Java資料持久層Java
- Spring 持久層整合Spring
- Multipath實現LUN裝置名稱的持久化持久化
- Redis 的持久化Redis持久化
- Redis的持久化Redis持久化
- 使用mongodb作為Quartz.Net下的JobStore實現底層的持久化機制MongoDBquartz持久化
- 河青的持久層框架hqbatis框架BAT
- AutoCRUD - PHP 下的透明持久層PHP
- OkHttp3實現Cookies管理及持久化HTTPCookie持久化
- Redis 必知必會之持久化Redis持久化
- Redis 持久化Redis持久化
- Redis - 持久化Redis持久化
- redisaof持久化Redis持久化
- ehcache持久化持久化
- Docker 持久化Docker持久化
- redis持久化Redis持久化
- [Redis]持久化Redis持久化
- 利用Kubernetes實現容器的持久化儲存持久化
- RDD持久化,不使用RDD持久化的問題的工作原理持久化
- 如何設計持久層才能方便而統一地管理事務和會話會話
- Java 持久層框架之 MyBatisJava框架MyBatis
- Redis的持久化方案Redis持久化
- Redis的持久化方式Redis持久化
- Redis的持久化策略Redis持久化
- Sentinel 實戰-規則持久化持久化
- Kafka實戰-資料持久化Kafka持久化
- webpack 持久化快取實踐Web持久化快取
- session會話的底層實現方式Session會話
- MyBatis--優秀的持久層框架MyBatis框架