/** * If the test method of the supplied {@link TestContext test context} is configured to run within * a transaction, this method will run {@link BeforeTransaction @BeforeTransaction methods} * and start a new transaction. * * <p>Note that if a {@code @BeforeTransaction} method fails, any remaining * {@code @BeforeTransaction} methods will not be invoked, and a transaction will not be started. * * @see org.springframework.transaction.annotation.Transactional * @see #getTransactionManager(TestContext, String) */ @SuppressWarnings("serial") @Override public void beforeTestMethod(TestContext testContext) throws Exception { final Method testMethod = testContext.getTestMethod(); Assert.notNull(testMethod, "The test method of the supplied TestContext must not be null"); if (this.transactionContextCache.remove(testMethod) != null) { throw new IllegalStateException( "Cannot start new transaction without ending existing transaction: " + "Invoke endTransaction() before startNewTransaction()."); } PlatformTransactionManager tm = null; TransactionAttribute transactionAttribute = this.attributeSource.getTransactionAttribute(testMethod, testContext.getTestClass()); if (transactionAttribute != null) { transactionAttribute = new DelegatingTransactionAttribute(transactionAttribute) { @Override public String getName() { return testMethod.getName(); } }; if (logger.isDebugEnabled()) { logger.debug( "Explicit transaction definition [" + transactionAttribute + "] found for test context " + testContext); } if (transactionAttribute.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NOT_SUPPORTED) { return; } tm = getTransactionManager(testContext, transactionAttribute.getQualifier()); } if (tm != null) { TransactionContext txContext = new TransactionContext(tm, transactionAttribute); runBeforeTransactionMethods(testContext); startNewTransaction(testContext, txContext); this.transactionContextCache.put(testMethod, txContext); } }
@Override public void rollback( PlatformTransactionManager platformTransactionManager, Throwable throwable, TransactionAttribute transactionAttribute, TransactionStatus transactionStatus) throws Throwable { if (transactionAttribute.rollbackOn(throwable)) { try { platformTransactionManager.rollback(transactionStatus); } catch (RuntimeException re) { re.addSuppressed(throwable); _log.error("Application exception overridden by rollback exception", re); throw re; } catch (Error e) { e.addSuppressed(throwable); _log.error("Application exception overridden by rollback error", e); throw e; } } else { commit(platformTransactionManager, transactionAttribute, transactionStatus); } throw throwable; }
/** * checks method (and as a fallback the class) for the Spring {@link Transactional} annotation. * * @param mi Non-null method invocation. * @return true if the {@link Transactional} annotation lists this method as read-only, or if no * annotation is found. */ boolean checkReadOnly(MethodInvocation mi) { TransactionAttribute ta = txSource.getTransactionAttribute(mi.getMethod(), mi.getThis().getClass()); return ta == null ? true : ta.isReadOnly(); }