Spring HibernateTransactionManager事物管理类(HibernateTransactionObject)

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

public class HibernateTransactionManager extends AbstractPlatformTransactionManager
		implements 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中获取DataSource
		if (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则是true
						TransactionSynchronizationManager.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()走完后,当前线程中就已经有两对值:

key value
sessionFactory sessionHolder
dataSource conHolder
4.现在这个主角类 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准备提交的方法等等......

更多详细查看 :

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







你可能感兴趣的:(Spring HibernateTransactionManager事物管理类(HibernateTransactionObject))