博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
java综合(六)hibernate.current_session_context_class配置
阅读量:3531 次
发布时间:2019-05-20

本文共 9406 字,大约阅读时间需要 31 分钟。

在前面一节"spring与Hibernate整合-事务"中,总是出现不存在激活事务的问题,结果去掉<prop key="hibernate.current_session_context_class">thread</prop>

但是,为什么呢?

那是因为在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,这个接口仅有一个方法:

SessioncurrentSession()                       throws HibernateExceptionRetrieve 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..

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

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 context = newThreadLocal();     . . .        //打开一个”事务提交后自动关闭”的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绑定到线程中:即以
键值对方式设置到线程局部量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
> resources; public static Object getResource(Object key) { Object actualKey = TransactionSynchronizationUtils.unwrapResourceIfNecessary(key); //在ThreadLocal的属性resources里查找Session, resources里以
的键值对存放到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")

总结: 

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 在上下文中的.

转载地址:http://znihj.baihongyu.com/

你可能感兴趣的文章
基于P5.js的“绘画系统”
查看>>
《达芬奇的人生密码》观后感
查看>>
论文翻译:《一个包容性设计的具体例子:聋人导向可访问性》
查看>>
基于“分形”编写的交互应用
查看>>
《融入动画技术的交互应用》主题博文推荐
查看>>
链睿和家乐福合作推出下一代零售业隐私保护技术
查看>>
Unifrax宣布新建SiFAB™生产线
查看>>
艾默生纪念谷轮™在空调和制冷领域的百年创新成就
查看>>
NEXO代币持有者获得20,428,359.89美元股息
查看>>
Piper Sandler为EverArc收购Perimeter Solutions提供咨询服务
查看>>
RMRK筹集600万美元,用于在Polkadot上建立先进的NFT系统标准
查看>>
JavaSE_day12 集合
查看>>
JavaSE_day14 集合中的Map集合_键值映射关系
查看>>
Day_15JavaSE 异常
查看>>
异常 Java学习Day_15
查看>>
JavaSE_day_03 方法
查看>>
day-03JavaSE_循环
查看>>
Mysql初始化的命令
查看>>
day_21_0817_Mysql
查看>>
day-22 mysql_SQL 结构化查询语言
查看>>