我们在Spring里通常把事务交给HibernateTransactionManager来处理,通过Aop配置事务,把事务交给该类之后就会由该类来帮我们管理和提供事务。这里它是怎么实现的,下面我们深入源码.....
public class HibernateTransactionManager extends AbstractPlatformTransactionManager implements ResourceTransactionManager, BeanFactoryAware, InitializingBean {
public abstract class AbstractPlatformTransactionManager implements PlatformTransactionManager, Serializable {
回到子类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); } }
设置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 |
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
TransactionDefinition:
http://book.51cto.com/art/200909/149403.htm