最近在做一个铁科院的医保项目框架是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对象,每次在用的时候只需要从这里面取出来就可以了。