No Sessionfound for current thread问题:hibernate.current_session_context_class

53 篇文章 0 订阅
19 篇文章 1 订阅

一、Q:在"springhibernate整合-事务"中,总是出现不存在激活事务的问题,结果去掉<prop key="hibernate.current_session_context_class">thread</prop>但是,为什么呢?

A:那是因为在Spring事务管理中,current Session是绑定到SpringSessionContext中的,而不是ThreadLocalSessionContext中的.



二、hibernate.current_session_context_class常用3种配置:jta,thread,org.springframework.orm.hibernate4.SpringSessionContext

从开Hibernate3.X开始,SessionFactory.getCurrentSession()的后台实现是可拔插的。因此,我们引入了新的扩展接口

 (org.hibernate.context.spi.CurrentSessionContext)和新的配置参数(hibernate.current_session_context_class),以便对什么是“当前session”的范围和上下文(scope and context)的定义进行拔插。它定义了单一的方法,currentSession(),特定的实现用它来负责跟踪当前的上下文session。


首先我们看看org.hibernate.context.spi.CurrentSessionContext,这个接口仅有一个方法:

[html]  view plain  copy
  1. SessioncurrentSession()  
  2.                        throws HibernateException  
  3. Retrieve thecurrent session according to the scoping defined by this implementation.  
currentSession()表示 根据当前CurrentSessionContext的实现及定义返回”当前的Session”这个接口…Hibernate中有3个类实现了这个接口

All Known Implementing Classes: TASessionContext, ManagedSessionContext, ThreadLocalSessionContext

1: org.hibernate.context.internal.ThreadLocalSessionContext - 当前session通过当前执行的线程来跟踪和界定。
 
2: org.hibernate.context.internal.JTASessionContext- 当前session根据JTA来跟踪和界定。这和以前的仅支持JTA的方法是完全一样的。
 
3: org.hibernate.context.internal.ManagedSessionContext..

4.Spring为事务管理,也实现了此接口:

 org.springframework.orm.hibernate4.SpringSessionContext            –当前Session根据Spring和事务管理器来跟踪和界定.


三、这几种实现都提供了“每个数据库事务对应一个session”的编程模型,也称作每次请求一个session。Hibernate session的起始和终结由数据库事务的生存来控制。

hibernate.current_session_context_class 配置参数定义了应该采用哪个org.hibernate.context.spi.CurrentSessionContext实现?

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()方法:

[html]  view plain  copy
  1. public final class SessionFactoryImpl    
  2.       implements SessionFactoryImplementor {    
  3.   . . .    
  4.   private final transient CurrentSessionContext currentSessionContext;    
  5.   . . .    
  6.   public Session getCurrentSession() throws HibernateException {    
  7.       if ( currentSessionContext == null ) {    
  8.          throw new HibernateException( "No CurrentSessionContext configured!" );    
  9.       }    
  10.       return currentSessionContext.currentSession();    
  11.   }    
  12.      
  13. . . .    
  14. }  

SessionFactoryImpl 的currentSessionContext属性的实际类型就是
由hibernate.current_session_context_class决定的…

2:首先设置: hibernate.current_session_context_class= org.hibernate.context.internal.ThreadLocalSessionContext
   到这一句,currentSessionContext.currentSession()跟进去

[html]  view plain  copy
  1. public class ThreadLocalSessionContext implements CurrentSessionContext {    
  2.     . . .    
  3.    private static final ThreadLocal<Map> context = newThreadLocal<Map>();    
  4.    . . .    
  5.      
  6.    //打开一个”事务提交后自动关闭”的Session    
  7.    protected Session buildOrObtainSession() {    
  8.        return factory.withOptions()    
  9.             .autoClose( isAutoCloseEnabled() )    
  10.             .connectionReleaseMode( getConnectionReleaseMode() )    
  11.             .flushBeforeCompletion( isAutoFlushEnabled() )    
  12.             .openSession();    
  13.     }    
  14.      
  15.     public final Session currentSession() throws HibernateException {    
  16.       //从线程局部量context中尝试取出已经绑定到线程的Session    
  17.       Session current = existingSession( factory );    
  18.          
  19.       //如果没有绑定到线程的Session    
  20.       if (current == null) {    
  21.          //打开一个”事务提交后自动关闭”的Session    
  22.          current = buildOrObtainSession();    
  23.             current.getTransaction().registerSynchronization(buildCleanupSynch() );    
  24.          // wrap the session in thetransaction-protection proxy    
  25.          if ( needsWrapping( current ) ) {    
  26.             current = wrap( current );    
  27.          }    
  28.          //将得到的Session绑定到线程中:即以<SessionFactory,Session>键值对方式设置到线程局部量context    
  29.          doBind( current, factory );    
  30.       }    
  31.       return current;    
  32.    }    
  33. . . .    
  34. }  

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

[html]  view plain  copy
  1. Public UserService    
  2. {    
  3.    @Transactional    
  4.    public void addUser(User user) throws Exception    
  5.    {    
  6.       Session session = sessionFactory.getCurrentSession();    
  7.          
  8.       session.save(user);    
  9.    }    
  10. }  

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

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

[html]  view plain  copy
  1. public class SpringSessionContext implements CurrentSessionContext {    
  2.      
  3.    private final SessionFactoryImplementor sessionFactory;    
  4.      
  5.      
  6.    -  - - - - -    
  7.      
  8.    public Session currentSession() throws HibernateException {    
  9.     //关键就是这一句,Spring实际上会去TransactionSynchronizationManager里查找”currentSession”    
  10.      
  11.     Object value = TransactionSynchronizationManager.getResource(this.sessionFactory);    
  12.       if (value instanceof Session) {    
  13.          return (Session) value;    
  14.       }    
  15.       else if (value instanceof SessionHolder) {    
  16.          SessionHolder sessionHolder = (SessionHolder) value;    
  17.          Session session = sessionHolder.getSession();    
  18.          if (TransactionSynchronizationManager.isSynchronizationActive()&&    
  19.                 !sessionHolder.isSynchronizedWithTransaction()) {    
  20.             TransactionSynchronizationManager.registerSynchronization(    
  21.                    new SpringSessionSynchronization(sessionHolder, this.sessionFactory));    
  22.             sessionHolder.setSynchronizedWithTransaction(true);    
  23.       
  24.             FlushMode flushMode = session.getFlushMode();    
  25.             if (FlushMode.isManualFlushMode(flushMode)&&    
  26.                    !TransactionSynchronizationManager.isCurrentTransactionReadOnly()){    
  27.                 session.setFlushMode(FlushMode.AUTO);    
  28.                 sessionHolder.setPreviousFlushMode(flushMode);    
  29.             }    
  30.          }    
  31.          return session;    
  32.       }    
  33.       else if (this.jtaSessionContext != null) {    
  34.          Session session = this.jtaSessionContext.currentSession();    
  35.          if (TransactionSynchronizationManager.isSynchronizationActive()){    
  36.             TransactionSynchronizationManager.registerSynchronization(newSpringFlushSynchronization(session));    
  37.          }    
  38.          return session;    
  39.       }    
  40.       else {    
  41.          throw new HibernateException("No Session found for current thread");    
  42.       }    
  43.    }    
  44.      
  45. }  

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

[html]  view plain  copy
  1. public abstract class TransactionSynchronizationManager {    
  2.      
  3.  . . .    
  4.  private static final ThreadLocal<Map<Object, Object>> resources;    
  5.      
  6.  public static Object getResource(Object key) {    
  7.       Object actualKey = TransactionSynchronizationUtils.unwrapResourceIfNecessary(key);    
  8.       //在ThreadLocal的属性resources里查找Session, resources里以<SessionFactory,SessionHolder>或 <SessionFactory,Session>的键值对存放到ThreadLocal的Map中    
  9.       Object value = doGetResource(actualKey);    
  10.       if (value != null && logger.isTraceEnabled()) {    
  11.          logger.trace("Retrievedvalue [" + value + "] for key [" + actualKey + "] bound to thread [" +    
  12.                 Thread.currentThread().getName() + "]");    
  13.       }    
  14.       return value;    
  15.    }    
  16.      
  17.  . ..    
  18. }  

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

总结: 

hibernate.current_session_context_class=thread(org.hibernate.context.internal.ThreadLocalSessionContext)
与 hibernate.current_session_context_class=org.springframework.orm.hibernate4.SpringSessionContext 时的SessionFactory.getCurrentSession()的不同之处在于: 
 (1)前者在ThreadLocalSessionContext里的线程局部的Map中查找Session,
 (2)而后者在SpringSessionContext的上下文(TransactionSynchronizationManager里的线程局部的Map)中查找...


      最终,你会发觉,无论是ThreadLocalSessionContext 或 SpringSessionContext 查找的"currentSession",都是以类似键值对<SessionFactory,Session>的形式存放到ThreadLocal的Map中,也就是说这两者的上下文都是一个ThreadLocal的Map...查找时以SessionFactory为键来查找对应的Session,所以在同一线程中,一个SessionFactory只能有一个currentSession

PS: 从中,我们也知道了,执行SessionFactoryImpl.openSession()时,只是简单地new 一个SessionBuilder,然后调用SessionBuilder.openSession(),得到的Session是不会绑定到任何 org.hibernate.context.spi.CurrentSessionContext 在上下文中。



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值