天天看點

轉 Spring @Transactional 聲明式事務管理 getCurrentSession

spring

@transactional聲明式事務管理

 getcurrentsession

在spring

@transactional聲明式事務管理的配置中,hibernate.current_session_context_class=thread…

這一句是不能加的…加了就會出錯..那為什麼不能加呢?

那是因為在spring事務管理中,current

session是綁定到springsessioncontext中的,而不是threadlocalsessioncontext中的

先結合bernate4.0說說:

從開

始,sessionfactory.getcurrentsession()的背景實作是可拔插的。是以,我們引入了新的擴充接口

(org.hibernate.context.spi.currentsessioncontext)和

新的配置參數(hibernate.current_session_context_class),以便對什麼是“目前session”的範圍和上下文(scope

and context)的定義進行拔插。

它定義

了單一的方法,currentsession(),特定的實作用它來負責跟蹤目前的上下文session。

這個接口僅有一個方法:

currentsession()

throws 

retrieve thecurrent session according to the scoping

defined by this implementation.

currentsession()表示

根據目前currentsessioncontext的實作及定義傳回”目前的session”

這個接口…hibernate中有3個類實作了這個接口

all known implementing classes:

, , 

1:

org.hibernate.context.internal.threadlocalsessioncontext -

目前session通過目前執行的線程來跟蹤和界定。

2:

org.hibernate.context.internal.jtasessioncontext-

目前session根據jta來跟蹤和界定。這和以前的僅支援jta的方法是完全一樣的。

3:

org.hibernate.context.internal.managedsessioncontext..

spring為事務管理,也實作了此接口:

1: org.springframework.orm.hibernate4.springsessioncontext–

目前session根據spring和事務管理器來跟蹤和界定.

這幾種實作都提供了“每資料庫事務對應一個session”的程式設計模型,也稱作每次請求一個session。hibernate session的起始和終結由資料庫事務的生存來控制。

hibernate.current_session_context_class

配置參數定義了應該采用哪個org.hibernate.context.spi.currentsessioncontext實作。

一般而言,此參數的值指明了要使用的實 現類的全名,但那兩個内置的實作可以使用簡寫,即"jta"和"thread"。

hibernate.current_session_context_class=thread

實質是:

hibernate.current_session_context_class= org.hibernate.context.internal.threadlocalsessioncontext

同理:

hibernate.current_session_context_class=jta

hibernate.current_session_context_class= org.hibernate.context.internal.jtasessioncontext

而在spring

@transactional聲明式事務管理,”currentsession”的定義為: 目前被 spring事務管理器

管理的session,此時應配置:

hibernate.current_session_context_class=org.springframework.orm.hibernate4.springsessioncontext

spring 整合hibernate管理事務後,由spring的transactionmanager管理事務後,

currentsession是綁定到springsessioncontext的,而不是thread。

此時hibernate.current_session_context_class應該是springsessioncontext,而它又會在使用localsessionfactorybean時自動的設定。

是以就不需要你去設定current_session_context_class

-   -      

- --         -

下面我們來分析一下sessionfactoryimpl, org.hibernate.context.spi.currentsessioncontext

org.hibernate.context.internal.threadlocalsessioncontext

org.springframework.orm.hibernate4.springsessioncontext

這些類的源代碼

分析sessionfactory.getcurrentsession() 我們跟進去

來到sessionfactoryimpl.getcurrentsession()方法:

sessionfactoryimpl

的currentsessioncontext屬性的實際類型就是

由hibernate.current_session_context_class決定的…

2:首先設定: hibernate.current_session_context_class= org.hibernate.context.internal.threadlocalsessioncontext

到這一句,currentsessioncontext.currentsession()跟進去

現在對于hibernate.current_session_context_class= thread時的getcurrentsession()就很清楚了:

1:嘗試取出綁定到線程的session

2:如果沒有,則開啟一個”事務送出後自動關閉”的session,并将此session加入到threadlocal的map中.

3:傳回session

3:然後再分析:hibernate.current_session_context_class=org.springframework.orm.hibernate4.springsessioncontext

因為加入了@transactional,執行adduser()方法時,spring的transactionmanager會自動open

sesion,自動開啟事務,并且将此sesion綁定到springsessioncontext(實際上是transactionsynchronizationmanager的threadlocal的map)中..

然後到sessionfactoryimpl.getcurrentsesssion()的currentsessioncontext.currentsession()這一句,跟進去

object value

=transactionsynchronizationmanager.getresource(this.sessionfactory);

關鍵是這一句,跟進去:

現在對于hibernate.current_session_context_class= org.springframework.orm.hibernate4.springsessioncontext時的getcurrentsession()就很清楚了:

@transactional聲明的方法執行時,spring的transactionmanager會自動open

2:sessionfactory.getcurrentsession()方法執行時,調用springsessioncontext.currentsession()從transactionsynchronizationmanager的上下文中查找

目前的session

3:找到後傳回目前的session,找不到,則傳回hibernateexception("no

sessionfound for current thread")

ps:

從中,我們也知道了,執行sessionfactoryimpl.opensession()時,隻是簡單地new

一個sessionbuilder,然後調用sessionbuilder.opensession(),得到的session是不會綁定到任何

org.hibernate.context.spi.currentsessioncontext

在上下文中的.

////////////////////////////////////////////////////////////////--------------------------------------------------------------------------------------------------------------------------------------- 

總結: hibernate.current_session_context_class=thread(org.hibernate.context.internal.threadlocalsessioncontext)

與    

 hibernate.current_session_context_class=org.springframework.orm.hibernate4.springsessioncontext

時的sessionfactory.getcurrentsession()的不同之處在于: 

 前者在threadlocalsessioncontext裡的線程局部的map中查找session,

 而後者在springsessioncontext的上下文(transactionsynchronizationmanager裡的線程局部的map)中查找...

最終,你會發覺,無論是threadlocalsessioncontext 或 springsessioncontext

查找的"currentsession",都是以類似鍵值對<sessionfactory,session>的形式存放到threadlocal的map中,也就是說這兩者的上下文都是一個threadlocal的map...查找時以sessionfactory為鍵來查找對應的session,是以在同一線程中,一個sessionfactory隻能有一個currentsession

轉自: