待整理
AbstractPlatformTransactionManager
public final TransactionStatus getTransaction(TransactionDefinition definition) throws TransactionException { Object transaction = doGetTransaction(); boolean debugEnabled = logger.isDebugEnabled(); if(definition == null) definition = new DefaultTransactionDefinition(); if(isExistingTransaction(transaction)) return handleExistingTransaction(definition, transaction, debugEnabled); if(definition.getTimeout() < -1) throw new InvalidTimeoutException("Invalid transaction timeout", definition.getTimeout()); if(definition.getPropagationBehavior() == 2) throw new IllegalTransactionStateException("No existing transaction found for transaction marked with propagation 'mandatory'"); if(definition.getPropagationBehavior() == 0 || definition.getPropagationBehavior() == 3 || definition.getPropagationBehavior() == 6) { SuspendedResourcesHolder suspendedResources = suspend(null); if(debugEnabled) logger.debug("Creating new transaction with name [" + definition.getName() + "]: " + definition); try { doBegin(transaction, definition); } catch(RuntimeException ex) { resume(null, suspendedResources); throw ex; } catch(Error err) { resume(null, suspendedResources); throw err; } boolean newSynchronization = getTransactionSynchronization() != 2; return newTransactionStatus(definition, transaction, true, newSynchronization, debugEnabled, suspendedResources); } else { boolean newSynchronization = getTransactionSynchronization() == 0; return newTransactionStatus(definition, null, true, newSynchronization, debugEnabled, null); } } private TransactionStatus handleExistingTransaction(TransactionDefinition definition, Object transaction, boolean debugEnabled) throws TransactionException { if(definition.getPropagationBehavior() == 5) throw new IllegalTransactionStateException("Existing transaction found for transaction marked with propagation 'never'"); if(definition.getPropagationBehavior() == 4) { if(debugEnabled) logger.debug("Suspending current transaction"); Object suspendedResources = suspend(transaction); boolean newSynchronization = getTransactionSynchronization() == 0; return newTransactionStatus(definition, null, false, newSynchronization, debugEnabled, suspendedResources); } if(definition.getPropagationBehavior() == 3) { if(debugEnabled) logger.debug("Suspending current transaction, creating new transaction with name [" + definition.getName() + "]"); SuspendedResourcesHolder suspendedResources = suspend(transaction); try { doBegin(transaction, definition); } catch(RuntimeException beginEx) { resumeAfterBeginException(transaction, suspendedResources, beginEx); throw beginEx; } catch(Error beginErr) { resumeAfterBeginException(transaction, suspendedResources, beginErr); throw beginErr; } boolean newSynchronization = getTransactionSynchronization() != 2; return newTransactionStatus(definition, transaction, true, newSynchronization, debugEnabled, suspendedResources); } boolean newSynchronization; if(definition.getPropagationBehavior() == 6) { if(!isNestedTransactionAllowed()) throw new NestedTransactionNotSupportedException("Transaction manager does not allow nested transactions by default - specify 'nestedTransactionAllowed' property with value 'true'"); if(debugEnabled) logger.debug("Creating nested transaction with name [" + definition.getName() + "]"); if(useSavepointForNestedTransaction()) { DefaultTransactionStatus status = newTransactionStatus(definition, transaction, false, false, debugEnabled, null); status.createAndHoldSavepoint(); return status; } else { doBegin(transaction, definition); newSynchronization = getTransactionSynchronization() != 2; return newTransactionStatus(definition, transaction, true, newSynchronization, debugEnabled, null); } } if(debugEnabled) logger.debug("Participating in existing transaction"); if(isValidateExistingTransaction()) { if(definition.getIsolationLevel() != -1) { Integer currentIsolationLevel = TransactionSynchronizationManager.getCurrentTransactionIsolationLevel(); if(currentIsolationLevel == null || currentIsolationLevel.intValue() != definition.getIsolationLevel()) { Constants isoConstants = DefaultTransactionDefinition.constants; throw new IllegalTransactionStateException("Participating transaction with definition [" + definition + "] specifies isolation level which is incompatible with existing transaction: " + (currentIsolationLevel == null ? "(unknown)" : isoConstants.toCode(currentIsolationLevel, "ISOLATION_"))); } } if(!definition.isReadOnly() && TransactionSynchronizationManager.isCurrentTransactionReadOnly()) throw new IllegalTransactionStateException("Participating transaction with definition [" + definition + "] is not marked as read-only but existing transaction is"); } currentIsolationLevel = getTransactionSynchronization() == 2 ? 0 : 1; return newTransactionStatus(definition, transaction, false, currentIsolationLevel, debugEnabled, null); } protected DefaultTransactionStatus newTransactionStatus(TransactionDefinition definition, Object transaction, boolean newTransaction, boolean newSynchronization, boolean debug, Object suspendedResources) { boolean actualNewSynchronization = newSynchronization && !TransactionSynchronizationManager.isSynchronizationActive(); if(actualNewSynchronization) { TransactionSynchronizationManager.setActualTransactionActive(transaction != null); TransactionSynchronizationManager.setCurrentTransactionIsolationLevel(definition.getIsolationLevel() == -1 ? null : new Integer(definition.getIsolationLevel())); TransactionSynchronizationManager.setCurrentTransactionReadOnly(definition.isReadOnly()); TransactionSynchronizationManager.setCurrentTransactionName(definition.getName()); TransactionSynchronizationManager.initSynchronization(); } return new DefaultTransactionStatus(transaction, newTransaction, actualNewSynchronization, definition.isReadOnly(), debug, suspendedResources); } protected int determineTimeout(TransactionDefinition definition) { if(definition.getTimeout() != -1) return definition.getTimeout(); else return defaultTimeout; } protected final SuspendedResourcesHolder suspend(Object transaction) throws TransactionException { if(TransactionSynchronizationManager.isSynchronizationActive()) { List suspendedSynchronizations = doSuspendSynchronization(); try { Object suspendedResources = null; if(transaction != null) suspendedResources = doSuspend(transaction); String name = TransactionSynchronizationManager.getCurrentTransactionName(); TransactionSynchronizationManager.setCurrentTransactionName(null); boolean readOnly = TransactionSynchronizationManager.isCurrentTransactionReadOnly(); TransactionSynchronizationManager.setCurrentTransactionReadOnly(false); Integer isolationLevel = TransactionSynchronizationManager.getCurrentTransactionIsolationLevel(); TransactionSynchronizationManager.setCurrentTransactionIsolationLevel(null); boolean wasActive = TransactionSynchronizationManager.isActualTransactionActive(); TransactionSynchronizationManager.setActualTransactionActive(false); return new SuspendedResourcesHolder(suspendedResources, suspendedSynchronizations, name, readOnly, isolationLevel, wasActive); } catch(RuntimeException ex) { doResumeSynchronization(suspendedSynchronizations); throw ex; } catch(Error err) { doResumeSynchronization(suspendedSynchronizations); throw err; } } if(transaction != null) { Object suspendedResources = doSuspend(transaction); return new SuspendedResourcesHolder(suspendedResources); } else { return null; } } protected final void resume(Object transaction, SuspendedResourcesHolder resourcesHolder) throws TransactionException { if(resourcesHolder != null) { Object suspendedResources = resourcesHolder.suspendedResources; if(suspendedResources != null) doResume(transaction, suspendedResources); List suspendedSynchronizations = resourcesHolder.suspendedSynchronizations; if(suspendedSynchronizations != null) { TransactionSynchronizationManager.setActualTransactionActive(resourcesHolder.wasActive); TransactionSynchronizationManager.setCurrentTransactionIsolationLevel(resourcesHolder.isolationLevel); TransactionSynchronizationManager.setCurrentTransactionReadOnly(resourcesHolder.readOnly); TransactionSynchronizationManager.setCurrentTransactionName(resourcesHolder.name); doResumeSynchronization(suspendedSynchronizations); } } } private void resumeAfterBeginException(Object transaction, SuspendedResourcesHolder suspendedResources, Throwable beginEx) { String exMessage = "Inner transaction begin exception overridden by outer transaction resume exception"; try { resume(transaction, suspendedResources); } catch(RuntimeException resumeEx) { logger.error(exMessage, beginEx); throw resumeEx; } catch(Error resumeErr) { logger.error(exMessage, beginEx); throw resumeErr; } } private List doSuspendSynchronization() { List suspendedSynchronizations = TransactionSynchronizationManager.getSynchronizations(); for(Iterator it = suspendedSynchronizations.iterator(); it.hasNext(); ((TransactionSynchronization)it.next()).suspend()); TransactionSynchronizationManager.clearSynchronization(); return suspendedSynchronizations; } private void doResumeSynchronization(List suspendedSynchronizations) { TransactionSynchronizationManager.initSynchronization(); TransactionSynchronization synchronization; for(Iterator it = suspendedSynchronizations.iterator(); it.hasNext(); TransactionSynchronizationManager.registerSynchronization(synchronization)) { synchronization = (TransactionSynchronization)it.next(); synchronization.resume(); } } public final void commit(TransactionStatus status) throws TransactionException { if(status.isCompleted()) throw new IllegalTransactionStateException("Transaction is already completed - do not call commit or rollback more than once per transaction"); DefaultTransactionStatus defStatus = (DefaultTransactionStatus)status; if(defStatus.isLocalRollbackOnly()) { if(defStatus.isDebug()) logger.debug("Transactional code has requested rollback"); processRollback(defStatus); return; } if(!shouldCommitOnGlobalRollbackOnly() && defStatus.isGlobalRollbackOnly()) { if(defStatus.isDebug()) logger.debug("Global transaction is marked as rollback-only but transactional code requested commit"); processRollback(defStatus); if(status.isNewTransaction() || isFailEarlyOnGlobalRollbackOnly()) throw new UnexpectedRollbackException("Transaction rolled back because it has been marked as rollback-only"); else return; } else { processCommit(defStatus); return; } } private void processCommit(DefaultTransactionStatus status) throws TransactionException { boolean beforeCompletionInvoked = false; try { prepareForCommit(status); triggerBeforeCommit(status); triggerBeforeCompletion(status); beforeCompletionInvoked = true; boolean globalRollbackOnly = false; if(status.isNewTransaction() || isFailEarlyOnGlobalRollbackOnly()) globalRollbackOnly = status.isGlobalRollbackOnly(); if(status.hasSavepoint()) { if(status.isDebug()) logger.debug("Releasing transaction savepoint"); status.releaseHeldSavepoint(); } else if(status.isNewTransaction()) { if(status.isDebug()) logger.debug("Initiating transaction commit"); doCommit(status); } if(globalRollbackOnly) throw new UnexpectedRollbackException("Transaction silently rolled back because it has been marked as rollback-only"); } catch(UnexpectedRollbackException ex) { triggerAfterCompletion(status, 1); throw ex; } catch(TransactionException ex) { if(isRollbackOnCommitFailure()) doRollbackOnCommitException(status, ex); else triggerAfterCompletion(status, 2); throw ex; } catch(RuntimeException ex) { if(!beforeCompletionInvoked) triggerBeforeCompletion(status); doRollbackOnCommitException(status, ex); throw ex; } catch(Error err) { if(!beforeCompletionInvoked) triggerBeforeCompletion(status); doRollbackOnCommitException(status, err); throw err; } triggerAfterCommit(status); triggerAfterCompletion(status, 0); break MISSING_BLOCK_LABEL_217; Exception exception; exception; triggerAfterCompletion(status, 0); throw exception; cleanupAfterCompletion(status); break MISSING_BLOCK_LABEL_235; Exception exception1; exception1; cleanupAfterCompletion(status); throw exception1; } public final void rollback(TransactionStatus status) throws TransactionException { if(status.isCompleted()) { throw new IllegalTransactionStateException("Transaction is already completed - do not call commit or rollback more than once per transaction"); } else { DefaultTransactionStatus defStatus = (DefaultTransactionStatus)status; processRollback(defStatus); return; } } private void processRollback(DefaultTransactionStatus status) { try { triggerBeforeCompletion(status); if(status.hasSavepoint()) { if(status.isDebug()) logger.debug("Rolling back transaction to savepoint"); status.rollbackToHeldSavepoint(); } else if(status.isNewTransaction()) { if(status.isDebug()) logger.debug("Initiating transaction rollback"); doRollback(status); } else if(status.hasTransaction()) { if(status.isLocalRollbackOnly() || isGlobalRollbackOnParticipationFailure()) { if(status.isDebug()) logger.debug("Participating transaction failed - marking existing transaction as rollback-only"); doSetRollbackOnly(status); } else if(status.isDebug()) logger.debug("Participating transaction failed - letting transaction originator decide on rollback"); } else { logger.debug("Should roll back transaction but cannot - no transaction available"); } } catch(RuntimeException ex) { triggerAfterCompletion(status, 2); throw ex; } catch(Error err) { triggerAfterCompletion(status, 2); throw err; } triggerAfterCompletion(status, 1); cleanupAfterCompletion(status); break MISSING_BLOCK_LABEL_197; Exception exception; exception; cleanupAfterCompletion(status); throw exception; } private void doRollbackOnCommitException(DefaultTransactionStatus status, Throwable ex) throws TransactionException { try { if(status.isNewTransaction()) { if(status.isDebug()) logger.debug("Initiating transaction rollback after commit exception", ex); doRollback(status); } else if(status.hasTransaction() && isGlobalRollbackOnParticipationFailure()) { if(status.isDebug()) logger.debug("Marking existing transaction as rollback-only after commit exception", ex); doSetRollbackOnly(status); } } catch(RuntimeException rbex) { logger.error("Commit exception overridden by rollback exception", ex); triggerAfterCompletion(status, 2); throw rbex; } catch(Error rberr) { logger.error("Commit exception overridden by rollback exception", ex); triggerAfterCompletion(status, 2); throw rberr; } triggerAfterCompletion(status, 1); } protected final void triggerBeforeCommit(DefaultTransactionStatus status) { if(status.isNewSynchronization()) { if(status.isDebug()) logger.trace("Triggering beforeCommit synchronization"); TransactionSynchronizationUtils.triggerBeforeCommit(status.isReadOnly()); } } protected final void triggerBeforeCompletion(DefaultTransactionStatus status) { if(status.isNewSynchronization()) { if(status.isDebug()) logger.trace("Triggering beforeCompletion synchronization"); TransactionSynchronizationUtils.triggerBeforeCompletion(); } } private void triggerAfterCommit(DefaultTransactionStatus status) { if(status.isNewSynchronization()) { if(status.isDebug()) logger.trace("Triggering afterCommit synchronization"); TransactionSynchronizationUtils.triggerAfterCommit(); } } private void triggerAfterCompletion(DefaultTransactionStatus status, int completionStatus) { if(status.isNewSynchronization()) { List synchronizations = TransactionSynchronizationManager.getSynchronizations(); if(!status.hasTransaction() || status.isNewTransaction()) { if(status.isDebug()) logger.trace("Triggering afterCompletion synchronization"); invokeAfterCompletion(synchronizations, completionStatus); } else { registerAfterCompletionWithExistingTransaction(status.getTransaction(), synchronizations); } } } protected final void invokeAfterCompletion(List synchronizations, int completionStatus) { TransactionSynchronizationUtils.invokeAfterCompletion(synchronizations, completionStatus); } private void cleanupAfterCompletion(DefaultTransactionStatus status) { status.setCompleted(); if(status.isNewSynchronization()) TransactionSynchronizationManager.clear(); if(status.isNewTransaction()) doCleanupAfterCompletion(status.getTransaction()); if(status.getSuspendedResources() != null) { if(status.isDebug()) logger.debug("Resuming suspended transaction"); resume(status.getTransaction(), (SuspendedResourcesHolder)status.getSuspendedResources()); } }
DataSourceTransactionManager
protected Object doGetTransaction() { DataSourceTransactionObject txObject = new DataSourceTransactionObject(); txObject.setSavepointAllowed(isNestedTransactionAllowed()); ConnectionHolder conHolder = (ConnectionHolder)TransactionSynchronizationManager.getResource(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 = dataSource.getConnection(); if(logger.isDebugEnabled()) 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(logger.isDebugEnabled()) 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, 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(dataSource); return conHolder; } protected void doResume(Object transaction, Object suspendedResources) { ConnectionHolder conHolder = (ConnectionHolder)suspendedResources; TransactionSynchronizationManager.bindResource(dataSource, conHolder); } protected void doCommit(DefaultTransactionStatus status) { DataSourceTransactionObject txObject = (DataSourceTransactionObject)status.getTransaction(); Connection con = txObject.getConnectionHolder().getConnection(); if(status.isDebug()) 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()) 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()) 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(dataSource); Connection con = txObject.getConnectionHolder().getConnection(); try { if(txObject.isMustRestoreAutoCommit()) con.setAutoCommit(true); DataSourceUtils.resetConnectionAfterTransaction(con, txObject.getPreviousIsolationLevel()); } catch(Throwable ex) { logger.debug("Could not reset JDBC Connection after transaction", ex); } if(txObject.isNewConnectionHolder()) { if(logger.isDebugEnabled()) logger.debug("Releasing JDBC Connection [" + con + "] after transaction"); DataSourceUtils.releaseConnection(con, dataSource); } txObject.getConnectionHolder().clear(); } private DataSource dataSource; }
HibernateTransactionManager