首页 > 代码库 > Spring事务管理接口PlatformTransactionManager的实现类DataSourceTransactionManager

Spring事务管理接口PlatformTransactionManager的实现类DataSourceTransactionManager

package org.springframework.jdbc.datasource;

import java.sql.Connection;
import java.sql.SQLException;
import javax.sql.DataSource;
import org.apache.commons.logging.Log;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.transaction.CannotCreateTransactionException;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.TransactionSystemException;
import org.springframework.transaction.support.AbstractPlatformTransactionManager;
import org.springframework.transaction.support.DefaultTransactionStatus;
import org.springframework.transaction.support.ResourceTransactionManager;
import org.springframework.transaction.support.TransactionSynchronizationManager;

public class DataSourceTransactionManager extends AbstractPlatformTransactionManager
  implements ResourceTransactionManager, InitializingBean
{
  private DataSource dataSource;

  public DataSourceTransactionManager()
  {
    setNestedTransactionAllowed(true);
  }

  public DataSourceTransactionManager(DataSource dataSource)
  {
    this();
    setDataSource(dataSource);
    afterPropertiesSet();
  }

  public void setDataSource(DataSource dataSource)
  {
    if ((dataSource instanceof TransactionAwareDataSourceProxy))
    {
      this.dataSource = ((TransactionAwareDataSourceProxy)dataSource).getTargetDataSource();
    }
    else
      this.dataSource = dataSource;
  }

  public DataSource getDataSource()
  {
    return this.dataSource;
  }

  public void afterPropertiesSet() {
    if (getDataSource() == null)
      throw new IllegalArgumentException("Property ‘dataSource‘ is required");
  }

  public Object getResourceFactory()
  {
    return getDataSource();
  }

  protected Object doGetTransaction() {
    DataSourceTransactionObject txObject = new DataSourceTransactionObject(null);
    txObject.setSavepointAllowed(isNestedTransactionAllowed());
    ConnectionHolder conHolder = (ConnectionHolder)TransactionSynchronizationManager.getResource(this.dataSource);

    txObject.setConnectionHolder(conHolder, false);
    return txObject;
  }

  protected boolean isExistingTransaction(Object transaction) {
    DataSourceTransactionObject txObject = (DataSourceTransactionObject)transaction;
    return (txObject.getConnectionHolder() != null) && (txObject.getConnectionHolder().isTransactionActive());
  }

  protected void doBegin(Object transaction, TransactionDefinition definition)
  {
    DataSourceTransactionObject txObject = (DataSourceTransactionObject)transaction;
    Connection con = null;
    try
    {
      if ((txObject.getConnectionHolder() == null) || (txObject.getConnectionHolder().isSynchronizedWithTransaction()))
      {
        Connection newCon = this.dataSource.getConnection();
        if (this.logger.isDebugEnabled()) {
          this.logger.debug("Acquired Connection [" + newCon + "] for JDBC transaction");
        }
        txObject.setConnectionHolder(new ConnectionHolder(newCon), true);
      }

      txObject.getConnectionHolder().setSynchronizedWithTransaction(true);
      con = txObject.getConnectionHolder().getConnection();

      Integer previousIsolationLevel = DataSourceUtils.prepareConnectionForTransaction(con, definition);
      txObject.setPreviousIsolationLevel(previousIsolationLevel);

      if (con.getAutoCommit()) {
        txObject.setMustRestoreAutoCommit(true);
        if (this.logger.isDebugEnabled()) {
          this.logger.debug("Switching JDBC Connection [" + con + "] to manual commit");
        }
        con.setAutoCommit(false);
      }
      txObject.getConnectionHolder().setTransactionActive(true);

      int timeout = determineTimeout(definition);
      if (timeout != -1) {
        txObject.getConnectionHolder().setTimeoutInSeconds(timeout);
      }

      if (txObject.isNewConnectionHolder()) {
        TransactionSynchronizationManager.bindResource(getDataSource(), txObject.getConnectionHolder());
      }
    }
    catch (SQLException ex)
    {
      DataSourceUtils.releaseConnection(con, this.dataSource);
      throw new CannotCreateTransactionException("Could not open JDBC Connection for transaction", ex);
    }
  }

  protected Object doSuspend(Object transaction) {
    DataSourceTransactionObject txObject = (DataSourceTransactionObject)transaction;
    txObject.setConnectionHolder(null);
    ConnectionHolder conHolder = (ConnectionHolder)TransactionSynchronizationManager.unbindResource(this.dataSource);

    return conHolder;
  }

  protected void doResume(Object transaction, Object suspendedResources) {
    ConnectionHolder conHolder = (ConnectionHolder)suspendedResources;
    TransactionSynchronizationManager.bindResource(this.dataSource, conHolder);
  }

  protected void doCommit(DefaultTransactionStatus status) {
    DataSourceTransactionObject txObject = (DataSourceTransactionObject)status.getTransaction();
    Connection con = txObject.getConnectionHolder().getConnection();
    if (status.isDebug())
      this.logger.debug("Committing JDBC transaction on Connection [" + con + "]");
    try
    {
      con.commit();
    }
    catch (SQLException ex) {
      throw new TransactionSystemException("Could not commit JDBC transaction", ex);
    }
  }

  protected void doRollback(DefaultTransactionStatus status) {
    DataSourceTransactionObject txObject = (DataSourceTransactionObject)status.getTransaction();
    Connection con = txObject.getConnectionHolder().getConnection();
    if (status.isDebug())
      this.logger.debug("Rolling back JDBC transaction on Connection [" + con + "]");
    try
    {
      con.rollback();
    }
    catch (SQLException ex) {
      throw new TransactionSystemException("Could not roll back JDBC transaction", ex);
    }
  }

  protected void doSetRollbackOnly(DefaultTransactionStatus status) {
    DataSourceTransactionObject txObject = (DataSourceTransactionObject)status.getTransaction();
    if (status.isDebug()) {
      this.logger.debug("Setting JDBC transaction [" + txObject.getConnectionHolder().getConnection() + "] rollback-only");
    }

    txObject.setRollbackOnly();
  }

  protected void doCleanupAfterCompletion(Object transaction) {
    DataSourceTransactionObject txObject = (DataSourceTransactionObject)transaction;

    if (txObject.isNewConnectionHolder()) {
      TransactionSynchronizationManager.unbindResource(this.dataSource);
    }

    Connection con = txObject.getConnectionHolder().getConnection();
    try {
      if (txObject.isMustRestoreAutoCommit()) {
        con.setAutoCommit(true);
      }
      DataSourceUtils.resetConnectionAfterTransaction(con, txObject.getPreviousIsolationLevel());
    }
    catch (Throwable ex) {
      this.logger.debug("Could not reset JDBC Connection after transaction", ex);
    }

    if (txObject.isNewConnectionHolder()) {
      if (this.logger.isDebugEnabled()) {
        this.logger.debug("Releasing JDBC Connection [" + con + "] after transaction");
      }
      DataSourceUtils.releaseConnection(con, this.dataSource);
    }

    txObject.getConnectionHolder().clear();
  }

  private static class DataSourceTransactionObject extends JdbcTransactionObjectSupport
  {
    private boolean newConnectionHolder;
    private boolean mustRestoreAutoCommit;

    public void setConnectionHolder(ConnectionHolder connectionHolder, boolean newConnectionHolder)
    {
      super.setConnectionHolder(connectionHolder);
      this.newConnectionHolder = newConnectionHolder;
    }

    public boolean isNewConnectionHolder() {
      return this.newConnectionHolder;
    }

    public boolean hasTransaction() {
      return (getConnectionHolder() != null) && (getConnectionHolder().isTransactionActive());
    }

    public void setMustRestoreAutoCommit(boolean mustRestoreAutoCommit) {
      this.mustRestoreAutoCommit = mustRestoreAutoCommit;
    }

    public boolean isMustRestoreAutoCommit() {
      return this.mustRestoreAutoCommit;
    }

    public void setRollbackOnly() {
      getConnectionHolder().setRollbackOnly();
    }

    public boolean isRollbackOnly() {
      return getConnectionHolder().isRollbackOnly();
    }
  }
}