Spring HibernateTransactionManager事物管理类(HibernateTransactionObject)

来源:互联网 发布:php轻量级论坛 编辑:程序博客网 时间:2024/04/19 02:11

我们在Spring里通常把事务交给HibernateTransactionManager来处理,通过Aop配置事务,把事务交给该类之后就会由该类来帮我们管理和提供事务。这里它是怎么实现的,下面我们深入源码.....

public class HibernateTransactionManager extends AbstractPlatformTransactionManagerimplements ResourceTransactionManager, BeanFactoryAware, InitializingBean {

首先该类继承了AbstractPlatformTransactionManager类且实现了一系列接口,

public abstract class AbstractPlatformTransactionManager implements PlatformTransactionManager, Serializable {

AbstractPlatformTransactionManager这个抽象类实现了接口的getTransaction(TransactionDefinition definition)方法,该方法中执行了doGetTransaction()、doBegin()方法以及其它方法,这里就不一一介绍了,

回到子类HibernateTransactionManager类,该类的重写了父类的doGetTransaction()方法和doBegin(),doCommit(),所以这个方法才是我们主要要讨论的,还有doCommit().........

从父类的getTransaction(TransactionDefinition definition)可以看出会先走doGetTransaction(),而后在走doBegin(),

我们来看doGetTransaction()方法源码:

protected Object doGetTransaction() {HibernateTransactionObject txObject = new HibernateTransactionObject();//这里new一个HibernateTransactionObject对象txObject.setSavepointAllowed(isNestedTransactionAllowed());//设置一个保存点               //从当前线程当中以sessionFacoty为key去取相对应的sessionHolder,SessionHolder sessionHolder =(SessionHolder) TransactionSynchronizationManager.getResource(getSessionFactory());if (sessionHolder != null) {if (logger.isDebugEnabled()) {logger.debug("Found thread-bound Session [" +SessionFactoryUtils.toString(sessionHolder.getSession()) + "] for Hibernate transaction");}txObject.setSessionHolder(sessionHolder);//把sessionHolder设置到txObject当中}else if (this.hibernateManagedSession) {//这是判断有没有设置在当前上下文,比如在配置文件中的thread,或Spring上下文try {Session session = getSessionFactory().getCurrentSession();//有就直接从当前上下文去取if (logger.isDebugEnabled()) {logger.debug("Found Hibernate-managed Session [" +SessionFactoryUtils.toString(session) + "] for Spring-managed transaction");}txObject.setExistingSession(session);//和上面一样设置sessionHolder到txObject当中,该set方法中又把session包装了下}catch (HibernateException ex) {throw new DataAccessResourceFailureException("Could not obtain Hibernate-managed Session for Spring-managed transaction", ex);}}               //在事务对象中设置DataSource,其中有个afterPropertiesSet()将从sessionFactory中获取DataSourceif (getDataSource() != null) {ConnectionHolder conHolder = (ConnectionHolder)TransactionSynchronizationManager.getResource(getDataSource());//从当前线程中获取绑定的数据库连接,它是在doBegin()方法绑定的txObject.setConnectionHolder(conHolder);//把从线程中取得的sessionHolder设置到txObject中}return txObject;}

上面这个doGetTransaction()方法走完了就创建了HibernateTransactionObject txObject对象,这个对象也是主角,且往这个对象中填充了两个属性,为这两个属性赋好值,一个是sessionholder,另一个是connectionHolder,也就是session和connect。

当你在业务逻辑里面的C方法里面包含A,B方法时同时调用,只开了一个事务,session还是当前线程里面的同一个,直接跑sessionFactoryUtils.dogetSession()。

分开在action调用时,先A后B,会为A开个事务,在为B开事务,但是从线程里面取session。


下一个就是doBegin()方法,引入一个新对象TransactionDefinition事物描述,有些代码省略.....

protected void doBegin(Object transaction, TransactionDefinition definition) {HibernateTransactionObject txObject = (HibernateTransactionObject) transaction;//取得txObject对象,把事务强转HibernateTransactionObject               // 如果sessionHolder没有创建,那么这里将会创建hibernate里面的session,并把这个session放到SessionHolder中Session session = null;try {//判断txObject上的sessionHolder值是否为空if (txObject.getSessionHolder() == null || txObject.getSessionHolder().isSynchronizedWithTransaction()) {Interceptor entityInterceptor = getEntityInterceptor();//一个实体拦截器Session newSession = (entityInterceptor != null ?getSessionFactory().openSession(entityInterceptor) : getSessionFactory().openSession());if (logger.isDebugEnabled()) {logger.debug("Opened new Session [" + SessionFactoryUtils.toString(newSession) +"] for Hibernate transaction");}txObject.setSession(newSession);}                       //这里从sessionHolder中取出session,为hibernateTransaction做准备session = txObject.getSessionHolder().getSession();if (this.prepareConnection && isSameConnectionForEntireSession(session)) {// We're allowed to change the transaction settings of the JDBC Connection.if (logger.isDebugEnabled()) {logger.debug("Preparing JDBC Connection of Hibernate Session [" + SessionFactoryUtils.toString(session) + "]");}Connection con = session.connection();Integer previousIsolationLevel = DataSourceUtils.prepareConnectionForTransaction(con, definition);txObject.setPreviousIsolationLevel(previousIsolationLevel);}else {  //这里是设置Aop里面你配置的isolation属性// Not allowed to change the transaction settings of the JDBC Connection.if (definition.getIsolationLevel() != TransactionDefinition.ISOLATION_DEFAULT) {// We should set a specific isolation level but are not allowed to...throw new InvalidIsolationLevelException("HibernateTransactionManager is not allowed to support custom isolation levels: " +"make sure that its 'prepareConnection' flag is on (the default) and that the " +"Hibernate connection release mode is set to 'on_close' (SpringTransactionFactory's default). " +"Make sure that your LocalSessionFactoryBean actually uses SpringTransactionFactory: Your " +"Hibernate properties should *not* include a 'hibernate.transaction.factory_class' property!");}if (logger.isDebugEnabled()) {logger.debug("Not preparing JDBC Connection of Hibernate Session [" + SessionFactoryUtils.toString(session) + "]");}} //这里是设置Aop里面你配置的read-only属性, if (definition.isReadOnly() && txObject.isNewSession()) { // Just set to NEVER in case of a new Session for this transaction. session.setFlushMode(FlushMode.MANUAL); } if (!definition.isReadOnly() && !txObject.isNewSession()) {//判断事物是否只读,是否是一个新的session,也就是当前线程里面存不存在session,不存在则为true(OpenSessionView)// We need AUTO or COMMIT for a non-read-only transaction.FlushMode flushMode = session.getFlushMode();if (flushMode.lessThan(FlushMode.COMMIT)) {session.setFlushMode(FlushMode.AUTO);txObject.getSessionHolder().setPreviousFlushMode(flushMode);}}Transaction hibTx;// Register transaction timeout.int timeout = determineTimeout(definition);if (timeout != TransactionDefinition.TIMEOUT_DEFAULT) {hibTx = session.getTransaction();//设置一个事务超时机制,设置时间hibTx.begin();hibTx.setTimeout(timeout);}else {//将hibernate的事务设置到txObject的sessionHolder的里面,这个sessionHolder会和线程绑定.hibTx = session.beginTransaction();} //将Transaction hibTx设置到txObject中,给txObject事务赋值,主要是一个已经开启的事务   txObject.getSessionHolder().setTransaction(hibTx);// Register the Hibernate Session's JDBC Connection for the DataSource, if set.if (getDataSource() != null) {         Connection con = session.connection();         ConnectionHolder conHolder = new ConnectionHolder(con);//包装connection     if (timeout != TransactionDefinition.TIMEOUT_DEFAULT) {              conHolder.setTimeoutInSeconds(timeout);      }     if (logger.isDebugEnabled()) {     logger.debug("Exposing Hibernate transaction as JDBC transaction [" + con + "]");     }     //把当前的数据库connection绑定在当前线程当中.     TransactionSynchronizationManager.bindResource(getDataSource(), conHolder);     //在这里给txObject的ConnectionHolder赋值,以保证在con不为null     txObject.setConnectionHolder(conHolder); }//如果是新的sessionHolder,将它和当前线程绑定// Bind the session holder to the thread.if (txObject.isNewSessionHolder()) {//判断在当前线程里面有没有这个sessionHolder,当前里面有则为false,open则是trueTransactionSynchronizationManager.bindResource(getSessionFactory(), txObject.getSessionHolder());//绑定到当前线程当中}//在sessionHolder中进行状态标志,标识事务已经开始。txObject.getSessionHolder().setSynchronizedWithTransaction(true);}}

上面这个doBegin方法,首先是得到一个在上面doGetTransaction()里面创建的hibernateTransactionObject对象txObject,还有个实体拦截器,entityInterceptor,该拦截器的作用就相当于一个代理,要访问被代理的对象,先走这个拦截器,我们在doGetTransaction方法中,先判断了在线程和当前上下文能不能取得到session,并把其设置到txObject中,并且还在doBegin()中为了保证sessionHolder不为null,判断同学txObject.getSessionHolder()如果为null,则通过sessionfactory打开一个session,并把它传到txObject封装成sessionHolder,且在opensession方法中传入拦截器,在打开session之前做事.

设置isolation,

read-only='true'时,虚拟事务,可以保证hibernate查询立刻发送sql语句.

1.走完doBegin(),txObject里面设置session和connect,在这个方法已经保证这两个值不为null,在doGetTrainsaction()方法是从线程里面取,如果没绑定,也就是null,在doBegin()中,保证了不为空,而session分为3中情况,1.OpensessionView,2.getCurrentSession(可以是thead或是spring上下文),3.opensession

上面源代码中的isNewSessionHolder()方法是返回这个session是否是一个新的,像OpensessionView则返回false,其它两中情况则是返回true,是新的则要绑定到线程当中.

2.得到的session在方法中开启了一个事务,并把事务存放到sessionHolder里,由于sessionHolder是绑定到线程当中,所以它的事务也将会同步

3.其中,还把数据库连接绑定到当前线程中去了,以数据库连接池datasouce为key,value是connectHolder.

总:doBegin()走完后,当前线程中就已经有两对值:

keyvaluesessionFactorysessionHolderdataSourceconHolder4.现在这个主角类HibernateTransactionObject对象txObject已经包含了sessionHolder,conHolder,已经开启了的Transaction。5.从doBegin()方法里面的判断sessionHolder是否为null,我们可以看出一个线程对应一个资源,保证一个线程里面只有一个session,一个connect,不能重复,因为线程里面的Map的key是唯一的,

Thread.currentThread——>t

t.threadLocals这个Map中包含的{key:ThreadLocal<Map>,value:Map},这里面的Map存放着session,connect。

protected void doCommit(DefaultTransactionStatus status) {//事务提交HibernateTransactionObject txObject = (HibernateTransactionObject) status.getTransaction();if (status.isDebug()) {logger.debug("Committing Hibernate transaction on Session [" +SessionFactoryUtils.toString(txObject.getSessionHolder().getSession()) + "]");}try {txObject.getSessionHolder().getTransaction().commit();//得到sessionHolder的事务,直接提交 }
doCommit()众所周知是事务提交,当然在提交之前,也做了些许多事情,比如清空session,这些方法就没一一列出.可以查看父类AbstractPlatformTransactionManager中的processCommit()方法, 可以看到是先跑一些prepareForCommit准备提交的方法等等......


绑定到线程上的事务,rollback.

更多详细查看 :

http://sailinglee.iteye.com/blog/598908

http://books.google.com.hk/books?id=jRVp2INtY1AC&pg=PA222&lpg=PA222&dq=HibernateTransactionManager#v=onepage&q=HibernateTransactionManager&f=false

TransactionDefinition:

http://book.51cto.com/art/200909/149403.htm







原创粉丝点击