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

it2022-05-05  181

编程式事务管理

在实际应用中,我们很少通过编程来进行事务管理。但是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.REQUIREDisolation指定事务隔离界别:通过org.springframework.transaction.annotation.Isolation 提供合法值。默认值:Isolation.DEFAULTreadOnly事务读写性。类型为:Boolean。默认值:falsetimeout设置超时时间,秒为单位,类型为:int。默认值:TransactionDefinition.TIMEOUT_DEFAULTrollbackFor异常情况进行回滚,类型为:Class<? extends Throwable>[]。默认值:{}rollbackForClassName异常情况进行回滚。类型为:String[]。默认值:{}noRollbackFor异常情况不会滚。类型为:Class<? extends Throwable>[]。默认值:{}noRollbackForClassName异常情况不会滚。类型为:String[]。默认值:{}

最新回复(0)