转 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。

首先我们看看org.hibernate.context.spi.CurrentSessionContext


这个接口仅有一个方法:

SessioncurrentSession()

throws HibernateException

Retrieve thecurrent session according to the scoping
defined by this implementation.

currentSession()表示
根据当前CurrentSessionContext的实现及定义返回”当前的Session”

 

这个接口…Hibernate中有3个类实现了这个接口

All Known Implementing Classes:

JTASessionContext, ManagedSessionContext, ThreadLocalSessionContext

 

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

这些类的源代码

 

1:
分析sessionFactory.getCurrentSession() 我们跟进去

来到SessionFactoryImpl.getCurrentSession()方法:


public final class SessionFactoryImpl
implements SessionFactoryImplementor {
. . .
private final transient CurrentSessionContext currentSessionContext;
. . .
public Session getCurrentSession() throws HibernateException {
if ( currentSessionContext == null ) {
throw new HibernateException( "No CurrentSessionContext configured!" );
}
return currentSessionContext.currentSession();
}

. . .
}

SessionFactoryImpl
的currentSessionContext属性的实际类型就是

由hibernate.current_session_context_class决定的…

 

2:首先设置: hibernate.current_session_context_class= org.hibernate.context.internal.ThreadLocalSessionContext

到这一句,currentSessionContext.currentSession()跟进去


public class ThreadLocalSessionContext implements CurrentSessionContext {
. . .
private static final ThreadLocal<Map> context = newThreadLocal<Map>();
. . .

//打开一个”事务提交后自动关闭”的Session
protected Session buildOrObtainSession() {
return factory.withOptions()
.autoClose( isAutoCloseEnabled() )
.connectionReleaseMode( getConnectionReleaseMode() )
.flushBeforeCompletion( isAutoFlushEnabled() )
.openSession();
}

public final Session currentSession() throws HibernateException {
//从线程局部量context中尝试取出已经绑定到线程的Session
Session current = existingSession( factory );

//如果没有绑定到线程的Session
if (current == null) {
//打开一个”事务提交后自动关闭”的Session
current = buildOrObtainSession();
current.getTransaction().registerSynchronization(buildCleanupSynch() );
// wrap the session in thetransaction-protection proxy
if ( needsWrapping( current ) ) {
current = wrap( current );
}
//将得到的Session绑定到线程中:即以<SessionFactory,Session>键值对方式设置到线程局部量context
doBind( current, factory );
}
return current;
}
. . .
}

现在对于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


Public UserService
{
@Transactional
public void addUser(User user) throws Exception
{
Session session = sessionFactory.getCurrentSession();

session.save(user);
}
}

因为加入了@Transactional,执行addUser()方法时,Spring的TransactionManager会自动Open
Sesion,自动开启事务,并且将此Sesion绑定到SpringSessionContext(实际上是TransactionSynchronizationManager的ThreadLocal的Map)中..

 

 

然后到SessionFactoryImpl.getCurrentSesssion()的currentSessionContext.currentSession()这一句,跟进去


public class SpringSessionContext implements CurrentSessionContext {

private final SessionFactoryImplementor sessionFactory;

- - - - - -

public Session currentSession() throws HibernateException {
//关键就是这一句,Spring实际上会去TransactionSynchronizationManager里查找”currentSession”

Object value = TransactionSynchronizationManager.getResource(this.sessionFactory);
if (value instanceof Session) {
return (Session) value;
}
else if (value instanceof SessionHolder) {
SessionHolder sessionHolder = (SessionHolder) value;
Session session = sessionHolder.getSession();
if (TransactionSynchronizationManager.isSynchronizationActive()&&
!sessionHolder.isSynchronizedWithTransaction()) {
TransactionSynchronizationManager.registerSynchronization(
new SpringSessionSynchronization(sessionHolder, this.sessionFactory));
sessionHolder.setSynchronizedWithTransaction(true);

FlushMode flushMode = session.getFlushMode();
if (FlushMode.isManualFlushMode(flushMode)&&
!TransactionSynchronizationManager.isCurrentTransactionReadOnly()){
session.setFlushMode(FlushMode.AUTO);
sessionHolder.setPreviousFlushMode(flushMode);
}
}
return session;
}
else if (this.jtaSessionContext != null) {
Session session = this.jtaSessionContext.currentSession();
if (TransactionSynchronizationManager.isSynchronizationActive()){
TransactionSynchronizationManager.registerSynchronization(newSpringFlushSynchronization(session));
}
return session;
}
else {
throw new HibernateException("No Session found for current thread");
}
}

}

Object value
=TransactionSynchronizationManager.getResource(this.sessionFactory);
关键是这一句,跟进去:


public abstract class TransactionSynchronizationManager {

. . .
private static final ThreadLocal<Map<Object, Object>> resources;

public static Object getResource(Object key) {
Object actualKey = TransactionSynchronizationUtils.unwrapResourceIfNecessary(key);
//在ThreadLocal的属性resources里查找Session, resources里以<SessionFactory,SessionHolder>或 <SessionFactory,Session>的键值对存放到ThreadLocal的Map中
Object value = doGetResource(actualKey);
if (value != null && logger.isTraceEnabled()) {
logger.trace("Retrievedvalue [" + value + "] for key [" + actualKey + "] bound to thread [" +
Thread.currentThread().getName() + "]");
}
return value;
}

. ..
}

现在对于hibernate.current_session_context_class= org.springframework.orm.hibernate4.SpringSessionContext时的getCurrentSession()就很清楚了:

 

 

1:
@Transactional声明的方法执行时,Spring的
TransactionManager会自动Open
Sesion,自动开启事务,并且将此Sesion绑定到SpringSessionContext(实际上是TransactionSynchronizationManager的ThreadLocal的Map)中..

 

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

转自:http://blog.csdn.net/irelandken/article/details/7193123

时间: 2024-10-06 03:51:36

转 Spring @Transactional 声明式事务管理 getCurrentSession的相关文章

spring mvc + mybatis + spring aop声明式事务管理没有作用

在最近的一个项目中,采用springMVC.mybatis,发现一个很恼人的问题:事务管理不起作用!!网上查阅了大量的资料,尝试了各种解决办法,亦未能解决问题! spring版本:3.0.5 mybatis版本:3.2.2 1.applicationContext.xml配置: mvc + mybatis + spring aop声明式事务管理没有作用" title="spring mvc + mybatis + spring aop声明式事务管理没有作用">2.spr

Spring学习之Spring的声明式事务管理详解

声明式事务管理 大多数Spring用户选择声明式事务管理的原因是,这个是对应用代码影响最小的选择,因此也最符合 非侵入式 轻量级容器的理念. Spring声明式事务管理可以在任何环境下使用.只需更改配置文件, 它就可以和JDBC.JDO.Hibernate或其他的事务机制一起工作. Spring的声明式事务管理可以被应用到任何类(以及那个类的实例)上. Spring提供了声明式的回滚规则. Spring允许你通过AOP定制事务行为.(例如,如果需要,你可以在事务回滚中插入定制的行为. 你也可以增

Spring的声明式事务管理&lt;tx:advice/&gt; 有关的设置

<tx:advice/> 有关的设置 这一节里将描述通过 <tx:advice/> 标签来指定不同的事务性设置.默认的 <tx:advice/> 设置如下: 事务传播设置是 REQUIRED 隔离级别是 DEFAULT 事务是 读/写 事务超时默认是依赖于事务系统的,或者事务超时没有被支持. 任何 RuntimeException 将触发事务回滚,但是任何 checked Exception 将不触发事务回滚 这些默认的设置当然也是可以被改变的. <tx:advi

spring aop 声明式事务管理

Spring使用AOP来完成声明式的事务管理   有annotation和xml两种形式 代码和上一篇基本相近,再贴一遍 两个实体类 package com.ouc.wkp.model; import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.Id; @Entity(name = "t_log") public class Log { priva

spring @Transactional 声明式事务

项目地址:[email protected]:witaste/transaction-annotation.git 情景一: A external method calls a method of the target object  外部方法调用目标对象的事务方法,异常逐层抛出,最终由a() 抛出,可以回滚. @Service public class FooServiceImpl implements FooService { @Autowired private FooMapper foo

spring 声明式事务管理注解方式实现

使用注解实现Spring的声明式事务管理,更加简单! 步骤: 1) 必须引入Aop相关的jar文件 2) bean.xml中指定注解方式实现声明式事务管理以及应用的事务管理器类 3)在需要添加事务控制的地方,写上: @Transactional @Transactional注解: 1)应用事务的注解 2)定义到方法上: 当前方法应用spring的声明式事务 3)定义到类上:   当前类的所有的方法都应用Spring声明式事务管理; 4)定义到父类上: 当执行父类的方法时候应用事务. 案例: 1.

全面分析 Spring 的编程式事务管理及声明式事务管理--转

开始之前 关于本教程 本教程将深入讲解 Spring 简单而强大的事务管理功能,包括编程式事务和声明式事务.通过对本教程的学习,您将能够理解 Spring 事务管理的本质,并灵活运用之. 先决条件 本教程假定您已经掌握了 Java 基础知识,并对 Spring 有一定了解.您还需要具备基本的事务管理的知识,比如:事务的定义,隔离级别的概念,等等.本文将直接使用这些概念而不做详细解释.另外,您最好掌握数据库的基础知识,虽然这不是必须. 系统需求 要试验这份教程中的工具和示例,硬件配置需求为:至少带

spring声明式事务管理

Spring 的声明式事务管理在底层是建立在 AOP 的基础之上的.其本质是对方法前后进行拦截,然后在目标方法开始之前创建或者加入一个事务,在执行完目标方法之后根据执行情况提交或者回滚事务. 声明式事务管理分为两种:1.配置文件   2.注解 1.配置文件(声明式事务管理)用法: 在applicationContext.xml配置文件中配置①事务管理器(事务管理者).②事务参数(事务通知).③AOP配置 如下: applicationContext.xml配置文件代码 1 <!-- 事务管理器(

分析 Spring 的编程式事务管理及声明式事务管理(转)

开始之前 关于本教程 本教程将深入讲解 Spring 简单而强大的事务管理功能,包括编程式事务和声明式事务.通过对本教程的学习,您将能够理解 Spring 事务管理的本质,并灵活运用之. 先决条件 本教程假定您已经掌握了 Java 基础知识,并对 Spring 有一定了解.您还需要具备基本的事务管理的知识,比如:事务的定义,隔离级别的概念,等等.本文将直接使用这些概念而不做详细解释.另外,您最好掌握数据库的基础知识,虽然这不是必须. 系统需求 要试验这份教程中的工具和示例,硬件配置需求为:至少带