Spring事务管理

阅读本篇博客前,请先了解OpenSessionInViewFilter是如何线程绑定session
	<bean id="transactionManager"
		class="org.springframework.orm.hibernate3.HibernateTransactionManager">
		<property name="sessionFactory">
			<ref bean="sf" />
		</property>
	</bean>

Hibernate结合Spring,Spring提供了org.springframework.orm.hibernate3.HibernateTransactionManager来管理Hibernate事务

下面是HibernateTransactionManager类部分源码的解析:

public class HibernateTransactionManager extends AbstractPlatformTransactionManager
         implements ResourceTransactionManager, BeanFactoryAware, InitializingBean {

	private SessionFactory sessionFactory;

	private DataSource dataSource;

	private boolean autodetectDataSource = true;

	private boolean prepareConnection = true;

	private boolean hibernateManagedSession = false;

	private boolean earlyFlushBeforeCommit = false;

	private Object entityInterceptor;

	private SQLExceptionTranslator jdbcExceptionTranslator;

	private SQLExceptionTranslator defaultJdbcExceptionTranslator;
	
	protected Object doGetTransaction() { 
		HibernateTransactionObject txObject = new HibernateTransactionObject();
		txObject.setSavepointAllowed(isNestedTransactionAllowed());

		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);
		}
		else if (this.hibernateManagedSession) {
			try {
				Session session = getSessionFactory().getCurrentSession();
				if (logger.isDebugEnabled()) {
					logger.debug("Found Hibernate-managed Session [" +
							SessionFactoryUtils.toString(session) + "] for Spring-managed transaction");
				}
				txObject.setExistingSession(session);
			}
			catch (HibernateException ex) {
				throw new DataAccessResourceFailureException(
						"Could not obtain Hibernate-managed Session for Spring-managed transaction", ex);
			}
		}

		if (getDataSource() != null) {
			ConnectionHolder conHolder = (ConnectionHolder)
					TransactionSynchronizationManager.getResource(getDataSource());
			txObject.setConnectionHolder(conHolder);
		}

		return txObject;
	}
	
	protected void doBegin(Object transaction, TransactionDefinition definition) {//transaction是HibernateTransactionObject,definition配置信息的描述
		HibernateTransactionObject txObject = (HibernateTransactionObject) transaction;

		if (txObject.hasConnectionHolder() && !txObject.getConnectionHolder().isSynchronizedWithTransaction()) {
			throw new IllegalTransactionStateException(
					"Pre-bound JDBC Connection found! HibernateTransactionManager does not support " +
					"running within DataSourceTransactionManager if told to manage the DataSource itself. " +
					"It is recommended to use a single HibernateTransactionManager for all transactions " +
					"on a single DataSource, no matter whether Hibernate or JDBC access.");
		}

		Session session = null;

		try {
			if (txObject.getSessionHolder() == null || txObject.getSessionHolder().isSynchronizedWithTransaction()) {//getSessionHolder()==null或者不是同步的就open一个Session并填充到SessionHolder同步
				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);
			}

			session = txObject.getSessionHolder().getSession();//获得上一步填充好的同步Session

			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 {
				// 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) + "]");
				}
			}

			if (definition.isReadOnly() && txObject.isNewSession()) {
				// Just set to NEVER in case of a new Session for this transaction.
				session.setFlushMode(FlushMode.NEVER);
			}

			if (!definition.isReadOnly() && !txObject.isNewSession()) {
				// We need AUTO or COMMIT for a non-read-only transaction.
				FlushMode flushMode = session.getFlushMode();
				if (flushMode.lessThan(FlushMode.COMMIT)) { //比较刷新数据库优先级,如果是COMMIT就设置为AUTO
					session.setFlushMode(FlushMode.AUTO);
					txObject.getSessionHolder().setPreviousFlushMode(flushMode);
				}
			}

			Transaction hibTx = null; //Hibernate事务

			// Register transaction timeout.
			int timeout = determineTimeout(definition); //超时时间
			if (timeout != TransactionDefinition.TIMEOUT_DEFAULT) { //!=-1说明没有超时
				// Use Hibernate's own transaction timeout mechanism on Hibernate 3.1
				// Applies to all statements, also to inserts, updates and deletes!
				hibTx = session.getTransaction();
				hibTx.setTimeout(timeout);
				hibTx.begin();
			}
			else {
				// Open a plain Hibernate transaction without specified timeout.
				hibTx = session.beginTransaction();
			}

			// Add the Hibernate transaction to the session holder.
			txObject.getSessionHolder().setTransaction(hibTx);//该事务是活动的

			// Register the Hibernate Session's JDBC Connection for the DataSource, if set.
			if (getDataSource() != null) { //对DataSource线程绑定
				Connection con = session.connection();
				ConnectionHolder conHolder = new ConnectionHolder(con);
				if (timeout != TransactionDefinition.TIMEOUT_DEFAULT) {
					conHolder.setTimeoutInSeconds(timeout);
				}
				if (logger.isDebugEnabled()) {
					logger.debug("Exposing Hibernate transaction as JDBC transaction [" + con + "]");
				}
				TransactionSynchronizationManager.bindResource(getDataSource(), conHolder);
				txObject.setConnectionHolder(conHolder);
			}

			// Bind the session holder to the thread.
			if (txObject.isNewSessionHolder()) { //isNewSessionHolder()保存的是该SessionHolder是否是同步的,如果不是说明是一个新的SessionHolder,所以要重新绑定到当前线程中。
				TransactionSynchronizationManager.bindResource(getSessionFactory(), txObject.getSessionHolder());
			}
			txObject.getSessionHolder().setSynchronizedWithTransaction(true); //最后标识事务已经同步
		}

		catch (Exception ex) {
			if (txObject.isNewSession()) {
				try {
					if (session.getTransaction().isActive()) {
						session.getTransaction().rollback();
					}
				}
				catch (Throwable ex2) {
					logger.debug("Could not rollback Session after failed transaction begin", ex);
				}
				finally {
					SessionFactoryUtils.closeSession(session);
				}
			}
			throw new CannotCreateTransactionException("Could not open Hibernate Session for transaction", ex);
		}
	}
	
	protected Object doSuspend(Object transaction) { //暂停事务,将所有绑定在线程上的资源解绑
		HibernateTransactionObject txObject = (HibernateTransactionObject) transaction;
		txObject.setSessionHolder(null);
		SessionHolder sessionHolder =
				(SessionHolder) TransactionSynchronizationManager.unbindResource(getSessionFactory());
		txObject.setConnectionHolder(null);
		ConnectionHolder connectionHolder = null;
		if (getDataSource() != null) {
			connectionHolder = (ConnectionHolder) TransactionSynchronizationManager.unbindResource(getDataSource());
		}
		return new SuspendedResourcesHolder(sessionHolder, connectionHolder);
	}

	protected void doResume(Object transaction, Object suspendedResources) { //恢复事务,重新sessionfactory和datasource绑定到线程上
		SuspendedResourcesHolder resourcesHolder = (SuspendedResourcesHolder) suspendedResources;
		if (TransactionSynchronizationManager.hasResource(getSessionFactory())) {
			// From non-transactional code running in active transaction synchronization
			// -> can be safely removed, will be closed on transaction completion.
			TransactionSynchronizationManager.unbindResource(getSessionFactory()); //为了保险绑定之前先对sessionfactory解绑
		}
		TransactionSynchronizationManager.bindResource(getSessionFactory(), resourcesHolder.getSessionHolder());
		if (getDataSource() != null) {
			TransactionSynchronizationManager.bindResource(getDataSource(), resourcesHolder.getConnectionHolder());
		}
	}
}

doGetTransaction()

1、如果使用了OpenSessionInViewFilter则获得已经绑定了当前线程的SessionHolder(以SessionFactory为key,Session为value绑定在当前线程中,至于如何绑定的看OpenSessionInViewFilter线程绑定session),如果是Hibernate事务管理则直接获得当前Session。

2、org.springframework.orm.hibernate3.SessionHolder:对Session的包装,并对保存了Session的Map做同步

public class SessionHolder extends ResourceHolderSupport {

private static final Object DEFAULT_KEY = new Object();

private final Map sessionMap = Collections.synchronizedMap(new HashMap(1));

private Transaction transaction;

private FlushMode previousFlushMode;

public SessionHolder(Session session) {
addSession(session);
}

public void addSession(Session session) {
addSession(DEFAULT_KEY, session);
}

public void addSession(Object key, Session session) {
Assert.notNull(key, "Key must not be null");
Assert.notNull(session, "Session must not be null");
this.sessionMap.put(key, session);
}

}

3、ConnectionHolder:对Connection一些信息的包装

public class ConnectionHolder extends ResourceHolderSupport {


public static final String SAVEPOINT_NAME_PREFIX = "SAVEPOINT_";

private ConnectionHandle connectionHandle;

private Connection currentConnection;

private boolean transactionActive = false;

private Boolean savepointsSupported;

private int savepointCounter = 0;

/**
* Create a new ConnectionHolder for the given ConnectionHandle.
* @param connectionHandle the ConnectionHandle to hold
*/
public ConnectionHolder(ConnectionHandle connectionHandle) {
Assert.notNull(connectionHandle, "ConnectionHandle must not be null");
this.connectionHandle = connectionHandle;
}


/**
* Create a new ConnectionHolder for the given JDBC Connection,
* wrapping it with a {@link SimpleConnectionHandle},
* assuming that there is no ongoing transaction.
* @param connection the JDBC Connection to hold
* @see SimpleConnectionHandle
* @see #ConnectionHolder(java.sql.Connection, boolean)
*/
public ConnectionHolder(Connection connection) {
this.connectionHandle = new SimpleConnectionHandle(connection);
}


/**
* Create a new ConnectionHolder for the given JDBC Connection,
* wrapping it with a {@link SimpleConnectionHandle}.
* @param connection the JDBC Connection to hold
* @param transactionActive whether the given Connection is involved
* in an ongoing transaction
* @see SimpleConnectionHandle
*/
public ConnectionHolder(Connection connection, boolean transactionActive) {
this(connection);
this.transactionActive = transactionActive;
}

}

②doBegin(Object transaction, TransactionDefinition definition):

1、txObject.setSession(newSession):

HibernateTransactionObject:

public void setSession(Session session) {
this.sessionHolder = new SessionHolder(session);
this.newSessionHolder = true;
this.newSession = true;
}

SessionHolder:

private final Map sessionMap = Collections.synchronizedMap(new HashMap(1));

public SessionHolder(Session session) {
addSession(session);
}

public void addSession(Session session) {
addSession(DEFAULT_KEY, session);
}

public void addSession(Object key, Session session) {
Assert.notNull(key, "Key must not be null");
Assert.notNull(session, "Session must not be null");
this.sessionMap.put(key, session);
}

最终将Session添加到了一个同步HashMap中

2、doBegin完成后当前线程中就 会有一个以ThreadLocal<Map>为key ,Map为value的ThreadLocal.ThreadLocalMap,并且ThreadLocal.ThreadLocalMap的value里又会有两对值,一个是以SessionFactory为key,session为value;一个是以DataSource为key,Connection为value;HibernateTransactionObjecttxObject = (HibernateTransactionObject) transaction;txObject则保存着绑定在同一线程中的session、connection还有已经开启的事务。


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值