zoukankan      html  css  js  c++  java
  • 转 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:

    JTASessionContextManagedSessionContextThreadLocalSessionContext

     

    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

  • 相关阅读:
    《圣女贞德》全技能合成表(psp)
    [转] 委外加工Procurement
    SAP HR TCode List
    IDES ABAP/4破解及client copy [转]
    [ SAP Interview ] SAP Basis Consultant Questionnaire
    [FI/CO] Controlling Question From Key User / Q & A
    SAP Monthly Closed
    [SAP Dictionary]
    UI Leader infragistic 2008 CLR download address link (Infragistics NetAdvantage For .NET 2008 CLR)
    SAP SubContract Processing
  • 原文地址:https://www.cnblogs.com/eason-chan/p/3709969.html
Copyright © 2011-2022 走看看