本文转自http://blog.csdn.net/irelandken/article/details/7193123
在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
相关推荐
本代码使用H2内存数据库演示spring事务使用,包括编程式事务,声明式事务@Transactional使用,自定义事务事务注解实现自定义事务管理器
主要介绍了Spring @Transactional工作原理详解,具有一定借鉴价值,需要的朋友可以参考下。
在本篇文章里小编给大家整理了关于Spring声明式事务@Transactional详解内容,需要的朋友们可以参考下。
我們使用Spring Framework裡,在Service 的 Method 給予@Transactional 系統就會去管理transaction,我們是在哪裡做了甚麼設定嗎? 為什麼下的這個Annotation成功會commit失敗會rollback呢? Transaction 管理做了...
Spring3事务管理——使用@Transactional 注解.rar
spring事务管理注解jar,spring-tx-3.2.4.RELEASE.jar,导入项目即可
使用@Transactional注解时,可以通过参数配置事务详情: 5.2.2 基于Annotation方式的声明式事务 * * * * * * * * 声明式事务管理 如何实现Spring的声明式事务管理? 5.2 声明式事务管理 Spring的声明式事务管理可以...
主要介绍了spring @Transactional 无效的解决方案,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
Spring中@Transactional事务回滚(含实例详细讲解,附源码)Java开发Java经验技巧共8页.pdf.zip
@Transactional实现原理.txt
今天小编就为大家分享一篇关于springboot中事务管理@Transactional的注意事项与使用场景,小编觉得内容挺不错的,现在分享给大家,具有很好的参考价值,需要的朋友一起跟随小编来看看吧
主要介绍了Spring @Transactional注解失效解决方案,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
此外,Spring事务管理器支持多种类型的事务策略,包括不同的传播行为和隔离级别,允许开发者根据具体业务场景选择最合适的事务管理策略。深入理解Spring声明式事务的工作原理,不仅能帮助开发者更高效地使用Spring...
本篇文章主要介绍了浅谈Spring中@Transactional事务回滚及示例(附源码),小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
声明式事务管理也有两种常用的方式,一种是基于tx和aop名字空间的xml配置文件,另一种就是基于@Transactional注解。显然基于注解的方式更简单易用,
Spring中的@Transactional事物回滚实例源码
主要介绍了深入学习Spring Boot排查 @Transactional 引起的 NullPointerException问题,需要的朋友可以参考下
注解实现声明式事务管理
今天我们来探讨一个有意思的spring源码问题,也是一个学生告诉了我现象我从源码里面找到了这个有意思的问题。 首先我们看service层的代码案例,如下: @Service("transationServiceImpl") public class ...