Spring事务管理

来源:互联网 发布:深圳软件产业基地网站 编辑:程序博客网 时间:2024/06/05 06:34
阅读本篇博客前,请先了解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();//获得上一步填充好的同步Sessionif (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就设置为AUTOsession.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;HibernateTransactionObject txObject = (HibernateTransactionObject) transaction;txObject则保存着绑定在同一线程中的session、connection还有已经开启的事务。