编程式事务
Spring 事务管理分为编程式和声明式的两种方式。编程式事务指的是通过编码方式实现事务;声明式事务基于 AOP,将具体业务逻辑与事务处理解耦,如常见的基于 @Transactional 注解的方式。本文将着重介绍基于TransactionTemplate的编程式事务管理。
基于TransactionTemplate
核心内容
核心方法源代码
public class TransactionTemplate extends DefaultTransactionDefinition
implements TransactionOperations, InitializingBean {
/** Logger available to subclasses. */
protected final Log logger = LogFactory.getLog(getClass());
@Nullable
private PlatformTransactionManager transactionManager;
/**
* 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.
* @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.
* @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.
*/
public void setTransactionManager(@Nullable PlatformTransactionManager transactionManager) {
this.transactionManager = transactionManager;
}
/**
* 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.
* @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())));
}
}
从上面代码可以看到 TransactionTemplate 实现了 TransactionOperations接口
public interface TransactionOperations {
@Nullable
<T> T execute(TransactionCallback<T> action) throws TransactionException;
default void executeWithoutResult(Consumer<TransactionStatus> action) throws TransactionException {
execute(status -> {
action.accept(status);
return null;
});
}
static TransactionOperations withoutTransaction() {
return WithoutTransactionOperations.INSTANCE;
}
}
而这个类有一个虚拟的扩展方法 executeWithoutResult ,这个方法适用于
执行一段简单的事务操作,不需要从回调返回对象或访问,并且可以方便的使用Lambda表达式。
无回调方法的使用
@Autowired
private TransactionTemplate transactionTemplate;
transactionTemplate.executeWithoutResult(t -> {
//这里写事务方法
a.insert(b);
});
再来看另一个方法 execute(),方法参数 TransactionCallback 里有一个方法
@FunctionalInterface
public interface TransactionCallback<T> {
@Nullable
T doInTransaction(TransactionStatus status);
}
实现此接口的抽象类
public abstract class TransactionCallbackWithoutResult implements TransactionCallback<Object> {
@Override
@Nullable
public final Object doInTransaction(TransactionStatus status) {
doInTransactionWithoutResult(status);
return null;
}
protected abstract void doInTransactionWithoutResult(TransactionStatus status);
}
可以看出 TransactionTemplate 的 execute 方法提供一个内部匿名类,用来写事物代码,然后提供一个TransactionStatus的 参数,用来控制回滚。
-
TransactionTemplate.execute( … )执行事务管理的时候,传入的参数有两种选择:
1. TransactionCallback //有返回值 2. TransactionCallbackWithoutResult //无返回值
有回调方法的使用
先注入模板类
@Autowired
private TransactionTemplate transactionTemplate;
- 带返回值-TransactionCallback
public Object xxx() {
transactionTemplate.execute(new TransactionCallback() {
@Override
public Object doInTransaction(TransactionStatus transactionStatus) {
Object result;
try {
// ... 事务方法
result = new Object();
return result;
} catch (Exception e) {
//回滚
transactionStatus.setRollbackOnly();
result = false;
return result;
}
}
});
}
//lamada 写法
public Object xxx() {
transactionTemplate.execute(transactionStatus->{
try {
// ... 事务方法
result = new Object();
return result;
} catch (Exception e) {
//回滚
transactionStatus.setRollbackOnly();
result = false;
return result;
}
});
}
2.无返回值-TransactionCallbackWithoutResult
public void xxx() {
transactionTemplate.execute(new TransactionCallbackWithoutResult() {
@Override
protected void doInTransactionWithoutResult(TransactionStatus transactionStatus) {
try {
// ... 事务方法
} catch (Exception e){
//回滚
transactionStatus.setRollbackOnly();
}
}
});
}
注: 事务方法可以不用显式的使用try,catch,手动回滚。TransactionTemplate会在遇到错误的时候自动回滚,不需要使用try,catch,适用于不需要捕获异常的场景。
transactionTemplate.execute(transactionStatus->{ //直接写业务代码,出现异常会自动回滚 });