天天看点

转 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

转自: