Save This Page
Home » Hibernate-3.3.2.GA » org.hibernate » transaction » [javadoc | source]
    1   /*
    2    * Hibernate, Relational Persistence for Idiomatic Java
    3    *
    4    * Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
    5    * indicated by the @author tags or express copyright attribution
    6    * statements applied by the authors.  All third-party contributions are
    7    * distributed under license by Red Hat Middleware LLC.
    8    *
    9    * This copyrighted material is made available to anyone wishing to use, modify,
   10    * copy, or redistribute it subject to the terms and conditions of the GNU
   11    * Lesser General Public License, as published by the Free Software Foundation.
   12    *
   13    * This program is distributed in the hope that it will be useful,
   14    * but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
   15    * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License
   16    * for more details.
   17    *
   18    * You should have received a copy of the GNU Lesser General Public License
   19    * along with this distribution; if not, write to:
   20    * Free Software Foundation, Inc.
   21    * 51 Franklin Street, Fifth Floor
   22    * Boston, MA  02110-1301  USA
   23    *
   24    */
   25   package org.hibernate.transaction;
   26   
   27   import java.sql.SQLException;
   28   import java.util.ArrayList;
   29   import java.util.List;
   30   import javax.transaction.Status;
   31   import javax.transaction.Synchronization;
   32   
   33   import org.slf4j.Logger;
   34   import org.slf4j.LoggerFactory;
   35   
   36   import org.hibernate.HibernateException;
   37   import org.hibernate.Transaction;
   38   import org.hibernate.TransactionException;
   39   import org.hibernate.jdbc.JDBCContext;
   40   
   41   /**
   42    * {@link Transaction} implementation based on transaction management through
   43    * a JDBC {@link java.sql.Connection}.
   44    * <p/>
   45    * This the Hibernate's default transaction strategy.
   46    *
   47    * @author Anton van Straaten
   48    * @author Gavin King
   49    */
   50   public class JDBCTransaction implements Transaction {
   51   
   52   	private static final Logger log = LoggerFactory.getLogger(JDBCTransaction.class);
   53   
   54   	private final JDBCContext jdbcContext;
   55   	private final TransactionFactory.Context transactionContext;
   56   
   57   	private boolean toggleAutoCommit;
   58   	private boolean begun;
   59   	private boolean rolledBack;
   60   	private boolean committed;
   61   	private boolean commitFailed;
   62   	private List synchronizations;
   63   	private boolean callback;
   64   	private int timeout = -1;
   65   
   66   	public JDBCTransaction(JDBCContext jdbcContext, TransactionFactory.Context transactionContext) {
   67   		this.jdbcContext = jdbcContext;
   68   		this.transactionContext = transactionContext;
   69   	}
   70   
   71   	/**
   72   	 * {@inheritDoc}
   73   	 */
   74   	public void begin() throws HibernateException {
   75   		if (begun) {
   76   			return;
   77   		}
   78   		if (commitFailed) {
   79   			throw new TransactionException("cannot re-start transaction after failed commit");
   80   		}
   81   
   82   		log.debug("begin");
   83   
   84   		try {
   85   			toggleAutoCommit = jdbcContext.connection().getAutoCommit();
   86   			if ( log.isDebugEnabled() ) {
   87   				log.debug("current autocommit status: " + toggleAutoCommit);
   88   			}
   89   			if (toggleAutoCommit) {
   90   				log.debug("disabling autocommit");
   91   				jdbcContext.connection().setAutoCommit(false);
   92   			}
   93   		}
   94   		catch (SQLException e) {
   95   			log.error("JDBC begin failed", e);
   96   			throw new TransactionException("JDBC begin failed: ", e);
   97   		}
   98   
   99   		callback = jdbcContext.registerCallbackIfNecessary();
  100   
  101   		begun = true;
  102   		committed = false;
  103   		rolledBack = false;
  104   
  105   		if ( timeout>0 ) {
  106   			jdbcContext.getConnectionManager()
  107   					.getBatcher()
  108   					.setTransactionTimeout(timeout);
  109   		}
  110   
  111   		jdbcContext.afterTransactionBegin(this);
  112   	}
  113   
  114   	private void closeIfRequired() throws HibernateException {
  115   		if ( callback && transactionContext.shouldAutoClose() && !transactionContext.isClosed() ) {
  116   			try {
  117   				transactionContext.managedClose();
  118   			}
  119   			catch (HibernateException he) {
  120   				log.error("Could not close session", he);
  121   				//swallow, the transaction was finished
  122   			}
  123   		}
  124   	}
  125   
  126   	/**
  127   	 * {@inheritDoc}
  128   	 */
  129   	public void commit() throws HibernateException {
  130   		if (!begun) {
  131   			throw new TransactionException("Transaction not successfully started");
  132   		}
  133   
  134   		log.debug("commit");
  135   
  136   		if ( !transactionContext.isFlushModeNever() && callback ) {
  137   			transactionContext.managedFlush(); //if an exception occurs during flush, user must call rollback()
  138   		}
  139   
  140   		notifyLocalSynchsBeforeTransactionCompletion();
  141   		if ( callback ) {
  142   			jdbcContext.beforeTransactionCompletion( this );
  143   		}
  144   
  145   		try {
  146   			commitAndResetAutoCommit();
  147   			log.debug("committed JDBC Connection");
  148   			committed = true;
  149   			if ( callback ) {
  150   				jdbcContext.afterTransactionCompletion( true, this );
  151   			}
  152   			notifyLocalSynchsAfterTransactionCompletion( Status.STATUS_COMMITTED );
  153   		}
  154   		catch (SQLException e) {
  155   			log.error("JDBC commit failed", e);
  156   			commitFailed = true;
  157   			if ( callback ) {
  158   				jdbcContext.afterTransactionCompletion( false, this );
  159   			}
  160   			notifyLocalSynchsAfterTransactionCompletion( Status.STATUS_UNKNOWN );
  161   			throw new TransactionException("JDBC commit failed", e);
  162   		}
  163   		finally {
  164   			closeIfRequired();
  165   		}
  166   	}
  167   
  168   	private void commitAndResetAutoCommit() throws SQLException {
  169   		try {
  170   			jdbcContext.connection().commit();
  171   		}
  172   		finally {
  173   			toggleAutoCommit();
  174   		}
  175   	}
  176   
  177   	/**
  178   	 * {@inheritDoc}
  179   	 */
  180   	public void rollback() throws HibernateException {
  181   
  182   		if (!begun && !commitFailed) {
  183   			throw new TransactionException("Transaction not successfully started");
  184   		}
  185   
  186   		log.debug("rollback");
  187   
  188   		if (!commitFailed) {
  189   
  190   			/*notifyLocalSynchsBeforeTransactionCompletion();
  191   			if ( callback ) {
  192   				jdbcContext.notifyLocalSynchsBeforeTransactionCompletion( this );
  193   			}*/
  194   
  195   			try {
  196   				rollbackAndResetAutoCommit();
  197   				log.debug("rolled back JDBC Connection");
  198   				rolledBack = true;
  199   				notifyLocalSynchsAfterTransactionCompletion(Status.STATUS_ROLLEDBACK);
  200   			}
  201   			catch (SQLException e) {
  202   				log.error("JDBC rollback failed", e);
  203   				notifyLocalSynchsAfterTransactionCompletion(Status.STATUS_UNKNOWN);
  204   				throw new TransactionException("JDBC rollback failed", e);
  205   			}
  206   			finally {
  207   				if ( callback ) {
  208   					jdbcContext.afterTransactionCompletion( false, this );
  209   				}
  210   				closeIfRequired();
  211   			}
  212   		}
  213   	}
  214   
  215   	private void rollbackAndResetAutoCommit() throws SQLException {
  216   		try {
  217   			jdbcContext.connection().rollback();
  218   		}
  219   		finally {
  220   			toggleAutoCommit();
  221   		}
  222   	}
  223   
  224   	private void toggleAutoCommit() {
  225   		try {
  226   			if (toggleAutoCommit) {
  227   				log.debug("re-enabling autocommit");
  228   				jdbcContext.connection().setAutoCommit( true );
  229   			}
  230   		}
  231   		catch (Exception sqle) {
  232   			log.error("Could not toggle autocommit", sqle);
  233   			//swallow it (the transaction _was_ successful or successfully rolled back)
  234   		}
  235   	}
  236   
  237   	/**
  238   	 * {@inheritDoc}
  239   	 */
  240   	public boolean wasRolledBack() {
  241   		return rolledBack;
  242   	}
  243   
  244   	/**
  245   	 * {@inheritDoc}
  246   	 */
  247   	public boolean wasCommitted() {
  248   		return committed;
  249   	}
  250   
  251   	/**
  252   	 * {@inheritDoc}
  253   	 */
  254   	public boolean isActive() {
  255   		return begun && ! ( rolledBack || committed | commitFailed );
  256   	}
  257   
  258   	/**
  259   	 * {@inheritDoc}
  260   	 */
  261   	public void registerSynchronization(Synchronization sync) throws HibernateException {
  262   		if (sync==null) throw new NullPointerException("null Synchronization");
  263   		if (synchronizations==null) {
  264   			synchronizations = new ArrayList();
  265   		}
  266   		synchronizations.add(sync);
  267   	}
  268   
  269   	private void notifyLocalSynchsBeforeTransactionCompletion() {
  270   		if (synchronizations!=null) {
  271   			for ( int i=0; i<synchronizations.size(); i++ ) {
  272   				Synchronization sync = (Synchronization) synchronizations.get(i);
  273   				try {
  274   					sync.beforeCompletion();
  275   				}
  276   				catch (Throwable t) {
  277   					log.error("exception calling user Synchronization", t);
  278   				}
  279   			}
  280   		}
  281   	}
  282   
  283   	private void notifyLocalSynchsAfterTransactionCompletion(int status) {
  284   		begun = false;
  285   		if (synchronizations!=null) {
  286   			for ( int i=0; i<synchronizations.size(); i++ ) {
  287   				Synchronization sync = (Synchronization) synchronizations.get(i);
  288   				try {
  289   					sync.afterCompletion(status);
  290   				}
  291   				catch (Throwable t) {
  292   					log.error("exception calling user Synchronization", t);
  293   				}
  294   			}
  295   		}
  296   	}
  297   
  298   	/**
  299   	 * {@inheritDoc}
  300   	 */
  301   	public void setTimeout(int seconds) {
  302   		timeout = seconds;
  303   	}
  304   }

Save This Page
Home » Hibernate-3.3.2.GA » org.hibernate » transaction » [javadoc | source]