Spring @Transactional 声明式事务管理 getCurrentSession

来源:互联网 发布:mysql 查询一年的数据 编辑:程序博客网 时间:2024/06/04 00:40

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

 

 

 

原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 魅蓝4g网速很慢怎么办 lol装到c盘了会怎么办 急用钱又借不到怎么办小额信贷 花呗分期买手机额度不够怎么办 2个月婴儿脸皴了怎么办 掉头发怎么办怎样能让头发变多 11个月的宝宝大便干燥怎么办 1岁宝宝又拉又吐怎么办 怀孕八个月了不想要了怎么办 奶水不够宝宝又不喝奶粉怎么办 手机恢复出厂设置密码忘了怎么办 5s锁屏密码忘了怎么办 深圳房子卖了户口没地方迁怎么办 宝马1系130i烧机怎么办 小孩流清鼻涕怎么办最简单方法 孕3个月胎盘低置怎么办 孩子判逆不听家长的话该怎么办 香港购物超5000被海关扣怎么办 浅色衣服被深色衣服染色了怎么办 金立手机微信不能发语音怎么办 吃鸡买的账号密码邮箱忘记了怎么办 氩弧焊枪管带里进水了怎么办 绝地求生穿头盔的时候连衣帽怎么办 开车不小心把光缆线给挂断了怎么办 脚刺到了生锈钢钉没打针怎么办 一加3t背壳螺丝掉了怎么办 30万美金美金中国被扣怎么办 电脑使用迅雷变的很卡怎么办 优盘拷贝过程中失去优盘路径怎么办 用百度云上传视频文件太慢了怎么办 网易云音乐云盘电脑上传很慢怎么办 路由器的宽带账号密码忘记了怎么办 蚂蚁邦路由器管理密码忘记了怎么办 红米2a刷机失败怎么办 小米手机开机图案锁忘记了怎么办 小米6进水无限闪屏开机重启怎么办 红米手机一直卡在开机画面怎么办 红米4卡在开机画面怎么办 红米手机一直在开机画面怎么办 红米手机一直跳开机画面怎么办 红米note3锁屏密码忘记怎么办