Spring事务(四、编程式事务管理以及声明式事务管理)

编程式事务管理

在实际应用中,我们很少通过编程来进行事务管理。但是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[]。默认值:{}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值