最近在做一个铁科院的医保项目框架是SSH,这种经典框架相信很多人对这个都很熟悉,不过对有些概念性的东西不知道你是否清楚,例如我们都知道hibernate通过session来操作数据库完成CRUD操作,Spring在同hibernate集成的时候可以将hibernate的sessionfactory拿过来管理,为了更方便操作数据库spring封装了一个getHibernateTemplate类,该类也可以完成CRUD操作,在使用灵活行方面比hibernate灵活了一些,操作也简便。
对数据库的操作都需要控制事务保证操作原子性,session在操作数据库的时候事务是怎么控制的呢,我们只知道事务是随着session一起开启和关闭的,具体来看一下是如何实现。
通过写底层的一些方法,了解了getCurrentSession()与openSession()的区别,前者是从当前线程中获取session,使用完后不需要自己关闭;后者是打开一个新的session,需要自己手动开发和关闭;
我们操作的是session,它和事务有什么关系呢?换句话说,session和事务生命周期是否相同?分别何时开启?何时关闭?
想要清楚这两者的关系,先要了解session机制,session是hibernate框架中一个操作ORM映射关系的接口,该接口有三种类型,分别为ThreadLocalSessionContext、JTASessionContext、ManagedSessionContext,这三个实现类实现了CurrentSessionContext接口。
getCurrentSession()这个方法得到的就是CurrentSessionContext接口,提供的默认实现类为ThreadLocalSessionContext
<span style="font-size:14px;">SessionFactory类 public abstract interface SessionFactory extends Referenceable, Serializable { public abstract Session openSession(Connection paramConnection); public abstract Session getCurrentSession() throws HibernateException; } SessionFactory实现类 public final class SessionFactoryImpl implements SessionFactory, SessionFactoryImplementor { private final transient CurrentSessionContext currentSessionContext; public Session getCurrentSession() throws HibernateException { if (this.currentSessionContext == null) { throw new HibernateException("No CurrentSessionContext configured!"); } return this.currentSessionContext.currentSession(); } } CurrentSessionContext接口里面只有一个方法,currentSession() public abstract interface CurrentSessionContext extends Serializable { public abstract Session currentSession() throws HibernateException; } public class ThreadLocalSessionContext implements CurrentSessionContext { private static final ThreadLocal context = new ThreadLocal(); public final org.hibernate.classic.Session currentSession() throws HibernateException { org.hibernate.classic.Session current = existingSession(this.factory); if (current == null) { current = buildOrObtainSession(); current.getTransaction().registerSynchronization(buildCleanupSynch()); if (needsWrapping(current)) { current = wrap(current); } doBind(current, this.factory); } return current; } } </span>
Session与Transaction进行关联是在底层session实现时操作的,你是否记得代理模式的作用,代理对象可以在客户端和目标对象之间起到中介的作用,可以增加一些额外,这样起到了保护目标对象的作用,在这里事务正式通过代理模式给session添加事务的
如果只从ThreadLocalSessionContext的名称上看,它所做的就是把一个session绑定到当前线程上,让当前线程作为session的上下文。这样,在service里不同的dao通过sessionFactory.getCurrentSession()得到的将是当前线程上的同一个session,这是非常必要的做法,通过使用同一个session确保了持久化对象的一致性。但是从ThreadLocalSessionContext的代码来看,它并只是做了这一件事,它还做了另外一件非常“醒目”的事情:即给session包裹了一层代理org.hibernate.context.ThreadLocalSessionContext$TransactionProtectionWrapper,这个代理将拦截session的操作,对session的使用做出了如下的限制:
1.在没有显式地开始一个事务之前,不能使用session的任何数据访问方法。
2.一旦事务提交,session将自动close。
通过上面这样的限制就使得事务同session的周期变的一致了,由于session放在了一个ThreadLocal里面,如此以来,threadlocal、session、transaction三者的生命周期是一致的,达到了对于同一个请求在同一个线程同一个事务中,session也是同一个session,既保证了持久化对象的一致性,又保证了事务的机制。
相反在提交事务之后,如果再从threadlocal中取得session将是一个新的session对象。因此,session的周期和事务是绑定在一起的。
ThreadLocal在这里当做上下文来存放session对象,每次在用的时候只需要从这里面取出来就可以了。