编程式事务管理
在实际应用中,我们很少通过编程来进行事务管理。但是Spring还是位编程式事务管理提供了模板类:TransactionTemplate
。其在org.springframework.transaction.support
包下。来满足一些特殊场合的需要。
所以下面主要说的就是基于TransactionTemplate
的编程式事务管理。
先看下例子:
public class TransactionTemplateTest {
@Resource
private TransactionTemplate transactionTemplate = new TransactionTemplate();
@Resource
private UserBalanceRepository userBalanceRepository;
/**
* 转账
*
* @param fromUser
* @param toUser
* @param balance
*/
public void addUserBalanceAndUser(User fromUser, User toUser, BigDecimal balance) {
transactionTemplate.execute(new TransactionCallbackWithoutResult() {
@Override
protected void doInTransactionWithoutResult(TransactionStatus status) {
final UserBalance fromUserBalance = userBalanceRepository.selectUserBalanceByUserIdForUpdate(fromUser.getUserId);
final UserBalance toUserBalance = userBalanceRepository.selectUserBalanceByUserIdForUpdate(fromUser.getUserId);
fromUserBalance.setBalance(fromUserBalance.getBalance().subtract(balance));
toUserBalance.setBalance(toUserBalance.getBalance().add(balance));
userBalanceRepository.updateById(fromUserBalance.getId());
userBalanceRepository.updateById(toUserBalance.getId());
// 异常回滚
status.setRollbackOnly();
}
});
}
}
看到先声明了一个TransactionTemplate
,然后调用了execute()
方法,并重写doInTransaction
方法时内部写入需要在事务中执行的代码。
看下TransactionTemplate
源代码:
TransactionTemplate
三个构造方法 以及 重写equals方法
其中调用了上一篇文章说过的PlatformTransactionManager
以及TransactionDefinition
/**
* 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;
}
@Override
public boolean equals(Object other) {
return (this == other || (super.equals(other) && (!(other instanceof TransactionTemplate) ||
getTransactionManager() == ((TransactionTemplate) other).getTransactionManager())));
}
一个没有内涵的重写方法 - 判断事务管理器是否为空
/**
* 判断事务管理器是否为空
*/
@Override
public void afterPropertiesSet() {
if (this.transactionManager == null) {
throw new IllegalArgumentException("Property 'transactionManager' is required");
}
}
两个与事务管理器有关方法
/**
* 设置事务管理器
*/
public void setTransactionManager(@Nullable PlatformTransactionManager transactionManager) {
this.transactionManager = transactionManager;
}
/**
* 获取事务管理器
*/
@Nullable
public PlatformTransactionManager getTransactionManager() {
return this.transactionManager;
}
最重要的excute方法
@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;
}
}
所以其实我们只需要调用transactionTemplate.execute()
方法,并再其重写方法中写入需要执行事务的代码就ok。
声明式事务管理
Spring 声明式事务管理是通过 SpringAOP实现的,通过事务的声明性信息,Spring负责将事务管理增强逻辑动态织入业务方法的相应连接点中、这些逻辑包括获取线程绑定资源、开始事务、提交/回滚事务、进行异常转换和处理等工作。
声明式事务管理又区分为:
- 使用XML配置声明式事务(不常用)
- 使用原始的TranSactionProxyFactoryBean(不常用)
- 使用< tx > 和< aop >命名空间的声明式事务管理(不常用)
- 使用@Transaction注解配置声明式事务(常用)
基于前三种确实不常用(我没用过,用过的读者就当我工龄尚浅或者low了吧),主要介绍:使用@Transaction注解配置声明式事务。
使用@Transaction注解配置声明式事务
明确一点既然是注解,来先看下注释源码
@Transaction 源码
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface Transactional {
/**
* Alias for {@link #transactionManager}.
* @see #transactionManager
*/
@AliasFor("transactionManager")
String value() default "";
/**
* A <em>qualifier</em> value for the specified transaction.
* <p>May be used to determine the target transaction manager,
* matching the qualifier value (or the bean name) of a specific
* {@link org.springframework.transaction.PlatformTransactionManager}
* bean definition.
* @since 4.2
* @see #value
*/
@AliasFor("value")
String transactionManager() default "";
/**
* The transaction propagation type.
* <p>Defaults to {@link Propagation#REQUIRED}.
* @see org.springframework.transaction.interceptor.TransactionAttribute#getPropagationBehavior()
*/
Propagation propagation() default Propagation.REQUIRED;
/**
* The transaction isolation level.
* <p>Defaults to {@link Isolation#DEFAULT}.
* @see org.springframework.transaction.interceptor.TransactionAttribute#getIsolationLevel()
*/
Isolation isolation() default Isolation.DEFAULT;
/**
* The timeout for this transaction.
* <p>Defaults to the default timeout of the underlying transaction system.
* @see org.springframework.transaction.interceptor.TransactionAttribute#getTimeout()
*/
int timeout() default TransactionDefinition.TIMEOUT_DEFAULT;
/**
* {@code true} if the transaction is read-only.
* <p>Defaults to {@code false}.
* <p>This just serves as a hint for the actual transaction subsystem;
* it will <i>not necessarily</i> cause failure of write access attempts.
* A transaction manager which cannot interpret the read-only hint will
* <i>not</i> throw an exception when asked for a read-only transaction
* but rather silently ignore the hint.
* @see org.springframework.transaction.interceptor.TransactionAttribute#isReadOnly()
*/
boolean readOnly() default false;
/**
* Defines zero (0) or more exception {@link Class classes}, which must be
* subclasses of {@link Throwable}, indicating which exception types must cause
* a transaction rollback.
* <p>By default, a transaction will be rolling back on {@link RuntimeException}
* and {@link Error} but not on checked exceptions (business exceptions). See
* {@link org.springframework.transaction.interceptor.DefaultTransactionAttribute#rollbackOn(Throwable)}
* for a detailed explanation.
* <p>This is the preferred way to construct a rollback rule (in contrast to
* {@link #rollbackForClassName}), matching the exception class and its subclasses.
* <p>Similar to {@link org.springframework.transaction.interceptor.RollbackRuleAttribute#RollbackRuleAttribute(Class clazz)}.
* @see #rollbackForClassName
* @see org.springframework.transaction.interceptor.DefaultTransactionAttribute#rollbackOn(Throwable)
*/
Class<? extends Throwable>[] rollbackFor() default {};
/**
* Defines zero (0) or more exception names (for exceptions which must be a
* subclass of {@link Throwable}), indicating which exception types must cause
* a transaction rollback.
* <p>This can be a substring of a fully qualified class name, with no wildcard
* support at present. For example, a value of {@code "ServletException"} would
* match {@code javax.servlet.ServletException} and its subclasses.
* <p><b>NB:</b> Consider carefully how specific the pattern is and whether
* to include package information (which isn't mandatory). For example,
* {@code "Exception"} will match nearly anything and will probably hide other
* rules. {@code "java.lang.Exception"} would be correct if {@code "Exception"}
* were meant to define a rule for all checked exceptions. With more unusual
* {@link Exception} names such as {@code "BaseBusinessException"} there is no
* need to use a FQN.
* <p>Similar to {@link org.springframework.transaction.interceptor.RollbackRuleAttribute#RollbackRuleAttribute(String exceptionName)}.
* @see #rollbackFor
* @see org.springframework.transaction.interceptor.DefaultTransactionAttribute#rollbackOn(Throwable)
*/
String[] rollbackForClassName() default {};
/**
* Defines zero (0) or more exception {@link Class Classes}, which must be
* subclasses of {@link Throwable}, indicating which exception types must
* <b>not</b> cause a transaction rollback.
* <p>This is the preferred way to construct a rollback rule (in contrast
* to {@link #noRollbackForClassName}), matching the exception class and
* its subclasses.
* <p>Similar to {@link org.springframework.transaction.interceptor.NoRollbackRuleAttribute#NoRollbackRuleAttribute(Class clazz)}.
* @see #noRollbackForClassName
* @see org.springframework.transaction.interceptor.DefaultTransactionAttribute#rollbackOn(Throwable)
*/
Class<? extends Throwable>[] noRollbackFor() default {};
/**
* Defines zero (0) or more exception names (for exceptions which must be a
* subclass of {@link Throwable}) indicating which exception types must <b>not</b>
* cause a transaction rollback.
* <p>See the description of {@link #rollbackForClassName} for further
* information on how the specified names are treated.
* <p>Similar to {@link org.springframework.transaction.interceptor.NoRollbackRuleAttribute#NoRollbackRuleAttribute(String exceptionName)}.
* @see #noRollbackFor
* @see org.springframework.transaction.interceptor.DefaultTransactionAttribute#rollbackOn(Throwable)
*/
String[] noRollbackForClassName() default {};
}
我们看到其中有很多参数,同时给定了默认值,整理一下
属性名 | 默认值 及 说明 |
---|---|
value(transactionManager) | value和transactionManager互为别名,主要来指定不同事务管理器;在同一个系统中,两种事务管理器txManager1, txManager2。通过这两个参数就可以使用该参数指定一个。 |
propagation | 指定事务传播行为:通过org.springframework.transaction.annotation.Propagation 提供合法值。默认值:Propagation.REQUIRED |
isolation | 指定事务隔离界别:通过org.springframework.transaction.annotation.Isolation 提供合法值。默认值:Isolation.DEFAULT |
readOnly | 事务读写性。类型为:Boolean。默认值:false |
timeout | 设置超时时间,秒为单位,类型为:int。默认值:TransactionDefinition.TIMEOUT_DEFAULT |
rollbackFor | 异常情况进行回滚,类型为:Class<? extends Throwable>[]。默认值:{} |
rollbackForClassName | 异常情况进行回滚。类型为:String[]。默认值:{} |
noRollbackFor | 异常情况不会滚。类型为:Class<? extends Throwable>[]。默认值:{} |
noRollbackForClassName | 异常情况不会滚。类型为:String[]。默认值:{} |