/*
* Copyright 2002-2018 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.transaction.support;
import java.lang.reflect.UndeclaredThrowableException;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.lang.Nullable;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.TransactionException;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.TransactionSystemException;
import org.springframework.util.Assert;
Template class that simplifies programmatic transaction demarcation and
transaction exception handling.
The central method is execute
, supporting transactional code that implements the TransactionCallback
interface. This template handles the transaction lifecycle and possible exceptions such that neither the TransactionCallback implementation nor the calling code needs to explicitly handle transactions.
Typical usage: Allows for writing low-level data access objects that use
resources such as JDBC DataSources but are not transaction-aware themselves.
Instead, they can implicitly participate in transactions handled by higher-level
application services utilizing this class, making calls to the low-level
services via an inner-class callback object.
Can be used within a service implementation via direct instantiation with
a transaction manager reference, or get prepared in an application context
and passed to services as bean reference. Note: The transaction manager should
always be configured as bean in the application context: in the first case given
to the service directly, in the second case given to the prepared template.
Supports setting the propagation behavior and the isolation level by name,
for convenient configuration in context definitions.
Author: Juergen Hoeller See Also: Since: 17.03.2003
/**
* Template class that simplifies programmatic transaction demarcation and
* transaction exception handling.
*
* <p>The central method is {@link #execute}, supporting transactional code that
* implements the {@link TransactionCallback} interface. This template handles
* the transaction lifecycle and possible exceptions such that neither the
* TransactionCallback implementation nor the calling code needs to explicitly
* handle transactions.
*
* <p>Typical usage: Allows for writing low-level data access objects that use
* resources such as JDBC DataSources but are not transaction-aware themselves.
* Instead, they can implicitly participate in transactions handled by higher-level
* application services utilizing this class, making calls to the low-level
* services via an inner-class callback object.
*
* <p>Can be used within a service implementation via direct instantiation with
* a transaction manager reference, or get prepared in an application context
* and passed to services as bean reference. Note: The transaction manager should
* always be configured as bean in the application context: in the first case given
* to the service directly, in the second case given to the prepared template.
*
* <p>Supports setting the propagation behavior and the isolation level by name,
* for convenient configuration in context definitions.
*
* @author Juergen Hoeller
* @since 17.03.2003
* @see #execute
* @see #setTransactionManager
* @see org.springframework.transaction.PlatformTransactionManager
*/
@SuppressWarnings("serial")
public class TransactionTemplate extends DefaultTransactionDefinition
implements TransactionOperations, InitializingBean {
Logger available to subclasses. /** Logger available to subclasses. */
protected final Log logger = LogFactory.getLog(getClass());
@Nullable
private PlatformTransactionManager transactionManager;
Construct a new TransactionTemplate for bean usage.
Note: The PlatformTransactionManager needs to be set before any execute
calls.
See Also:
/**
* Construct a new TransactionTemplate for bean usage.
* <p>Note: The PlatformTransactionManager needs to be set before
* any {@code execute} calls.
* @see #setTransactionManager
*/
public TransactionTemplate() {
}
Construct a new TransactionTemplate using the given transaction manager.
Params: - transactionManager – the transaction management strategy to be used
/**
* Construct a new TransactionTemplate using the given transaction manager.
* @param transactionManager the transaction management strategy to be used
*/
public TransactionTemplate(PlatformTransactionManager transactionManager) {
this.transactionManager = transactionManager;
}
Construct a new TransactionTemplate using the given transaction manager,
taking its default settings from the given transaction definition.
Params: - transactionManager – the transaction management strategy to be used
- transactionDefinition – the transaction definition to copy the
default settings from. Local properties can still be set to change values.
/**
* Construct a new TransactionTemplate using the given transaction manager,
* taking its default settings from the given transaction definition.
* @param transactionManager the transaction management strategy to be used
* @param transactionDefinition the transaction definition to copy the
* default settings from. Local properties can still be set to change values.
*/
public TransactionTemplate(PlatformTransactionManager transactionManager, TransactionDefinition transactionDefinition) {
super(transactionDefinition);
this.transactionManager = transactionManager;
}
Set the transaction management strategy to be used.
/**
* Set the transaction management strategy to be used.
*/
public void setTransactionManager(@Nullable PlatformTransactionManager transactionManager) {
this.transactionManager = transactionManager;
}
Return the transaction management strategy to be used.
/**
* Return the transaction management strategy to be used.
*/
@Nullable
public PlatformTransactionManager getTransactionManager() {
return this.transactionManager;
}
@Override
public void afterPropertiesSet() {
if (this.transactionManager == null) {
throw new IllegalArgumentException("Property 'transactionManager' is required");
}
}
@Override
@Nullable
public <T> T execute(TransactionCallback<T> action) throws TransactionException {
Assert.state(this.transactionManager != null, "No PlatformTransactionManager set");
if (this.transactionManager instanceof CallbackPreferringPlatformTransactionManager) {
return ((CallbackPreferringPlatformTransactionManager) this.transactionManager).execute(this, action);
}
else {
TransactionStatus status = this.transactionManager.getTransaction(this);
T result;
try {
result = action.doInTransaction(status);
}
catch (RuntimeException | Error ex) {
// Transactional code threw application exception -> rollback
rollbackOnException(status, ex);
throw ex;
}
catch (Throwable ex) {
// Transactional code threw unexpected exception -> rollback
rollbackOnException(status, ex);
throw new UndeclaredThrowableException(ex, "TransactionCallback threw undeclared checked exception");
}
this.transactionManager.commit(status);
return result;
}
}
Perform a rollback, handling rollback exceptions properly.
Params: - status – object representing the transaction
- ex – the thrown application exception or error
Throws: - TransactionException – in case of a rollback error
/**
* Perform a rollback, handling rollback exceptions properly.
* @param status object representing the transaction
* @param ex the thrown application exception or error
* @throws TransactionException in case of a rollback error
*/
private void rollbackOnException(TransactionStatus status, Throwable ex) throws TransactionException {
Assert.state(this.transactionManager != null, "No PlatformTransactionManager set");
logger.debug("Initiating transaction rollback on application exception", ex);
try {
this.transactionManager.rollback(status);
}
catch (TransactionSystemException ex2) {
logger.error("Application exception overridden by rollback exception", ex);
ex2.initApplicationException(ex);
throw ex2;
}
catch (RuntimeException | Error ex2) {
logger.error("Application exception overridden by rollback exception", ex);
throw ex2;
}
}
@Override
public boolean equals(@Nullable Object other) {
return (this == other || (super.equals(other) && (!(other instanceof TransactionTemplate) ||
getTransactionManager() == ((TransactionTemplate) other).getTransactionManager())));
}
}