Springboot事务处理

简介: Springboot事务处理

一、事务处理

1、springboot事务介绍

Spring采用统一的机制来处理不同的数据访问技术的事务, Spring的事务提供一个PlatformTransactionManager的接口,不同的数据访问技术使用不同的接口实现。

Data Tech 实现
JDBC DataSourceTransactionManager
JPA JPATransactionManager
Hibernate HibernateTransactionManager
JDO JDOTransactionManager
分布式事务 JtaTransactionManager

涉及到接口关系如下:

接口PlatformTransactionManager源码如下

/*
 * Copyright 2002-2012 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
 *
 *      http://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;
 
import org.springframework.lang.Nullable;
 
/**
 * This is the central interface in Spring's transaction infrastructure.
 * Applications can use this directly, but it is not primarily meant as API:
 * Typically, applications will work with either TransactionTemplate or
 * declarative transaction demarcation through AOP.
 *
 * <p>For implementors, it is recommended to derive from the provided
 * {@link org.springframework.transaction.support.AbstractPlatformTransactionManager}
 * class, which pre-implements the defined propagation behavior and takes care
 * of transaction synchronization handling. Subclasses have to implement
 * template methods for specific states of the underlying transaction,
 * for example: begin, suspend, resume, commit.
 *
 * <p>The default implementations of this strategy interface are
 * {@link org.springframework.transaction.jta.JtaTransactionManager} and
 * {@link org.springframework.jdbc.datasource.DataSourceTransactionManager},
 * which can serve as an implementation guide for other transaction strategies.
 *
 * @author Rod Johnson
 * @author Juergen Hoeller
 * @since 16.05.2003
 * @see org.springframework.transaction.support.TransactionTemplate
 * @see org.springframework.transaction.interceptor.TransactionInterceptor
 * @see org.springframework.transaction.interceptor.TransactionProxyFactoryBean
 */
public interface PlatformTransactionManager {
 
  /**
   * Return a currently active transaction or create a new one, according to
   * the specified propagation behavior.
   * <p>Note that parameters like isolation level or timeout will only be applied
   * to new transactions, and thus be ignored when participating in active ones.
   * <p>Furthermore, not all transaction definition settings will be supported
   * by every transaction manager: A proper transaction manager implementation
   * should throw an exception when unsupported settings are encountered.
   * <p>An exception to the above rule is the read-only flag, which should be
   * ignored if no explicit read-only mode is supported. Essentially, the
   * read-only flag is just a hint for potential optimization.
   * @param definition TransactionDefinition instance (can be {@code null} for defaults),
   * describing propagation behavior, isolation level, timeout etc.
   * @return transaction status object representing the new or current transaction
   * @throws TransactionException in case of lookup, creation, or system errors
   * @throws IllegalTransactionStateException if the given transaction definition
   * cannot be executed (for example, if a currently active transaction is in
   * conflict with the specified propagation behavior)
   * @see TransactionDefinition#getPropagationBehavior
   * @see TransactionDefinition#getIsolationLevel
   * @see TransactionDefinition#getTimeout
   * @see TransactionDefinition#isReadOnly
   */
  TransactionStatus getTransaction(@Nullable TransactionDefinition definition) throws TransactionException;
 
  /**
   * Commit the given transaction, with regard to its status. If the transaction
   * has been marked rollback-only programmatically, perform a rollback.
   * <p>If the transaction wasn't a new one, omit the commit for proper
   * participation in the surrounding transaction. If a previous transaction
   * has been suspended to be able to create a new one, resume the previous
   * transaction after committing the new one.
   * <p>Note that when the commit call completes, no matter if normally or
   * throwing an exception, the transaction must be fully completed and
   * cleaned up. No rollback call should be expected in such a case.
   * <p>If this method throws an exception other than a TransactionException,
   * then some before-commit error caused the commit attempt to fail. For
   * example, an O/R Mapping tool might have tried to flush changes to the
   * database right before commit, with the resulting DataAccessException
   * causing the transaction to fail. The original exception will be
   * propagated to the caller of this commit method in such a case.
   * @param status object returned by the {@code getTransaction} method
   * @throws UnexpectedRollbackException in case of an unexpected rollback
   * that the transaction coordinator initiated
   * @throws HeuristicCompletionException in case of a transaction failure
   * caused by a heuristic decision on the side of the transaction coordinator
   * @throws TransactionSystemException in case of commit or system errors
   * (typically caused by fundamental resource failures)
   * @throws IllegalTransactionStateException if the given transaction
   * is already completed (that is, committed or rolled back)
   * @see TransactionStatus#setRollbackOnly
   */
  void commit(TransactionStatus status) throws TransactionException;
 
  /**
   * Perform a rollback of the given transaction.
   * <p>If the transaction wasn't a new one, just set it rollback-only for proper
   * participation in the surrounding transaction. If a previous transaction
   * has been suspended to be able to create a new one, resume the previous
   * transaction after rolling back the new one.
   * <p><b>Do not call rollback on a transaction if commit threw an exception.</b>
   * The transaction will already have been completed and cleaned up when commit
   * returns, even in case of a commit exception. Consequently, a rollback call
   * after commit failure will lead to an IllegalTransactionStateException.
   * @param status object returned by the {@code getTransaction} method
   * @throws TransactionSystemException in case of rollback or system errors
   * (typically caused by fundamental resource failures)
   * @throws IllegalTransactionStateException if the given transaction
   * is already completed (that is, committed or rolled back)
   */
  void rollback(TransactionStatus status) throws TransactionException;
 
}

而得益于SpringBoot的自动配置机制,为我们自动开启了声明式事务支持, 我们无需添加注解@EnableTransactionManagement

Spring提供一个@EnableTransactionManagement注解在配置类上开启声明式事务支持, 自动扫描加了@Transactional注解的类和方法,加入事务支持。

一下为Transactional源码

package org.springframework.transaction.annotation;
 
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
 
import org.springframework.core.annotation.AliasFor;
import org.springframework.transaction.TransactionDefinition;
 
 
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface Transactional {
 
  @AliasFor("transactionManager")
  String value() default "";
  
  @AliasFor("value")
  String transactionManager() default "";
  
  Propagation propagation() default Propagation.REQUIRED;
 
  Isolation isolation() default Isolation.DEFAULT;
 
  int timeout() default TransactionDefinition.TIMEOUT_DEFAULT;
 
  boolean readOnly() default false;
 
  Class<? extends Throwable>[] rollbackFor() default {};
 
  String[] rollbackForClassName() default {};
  
  Class<? extends Throwable>[] noRollbackFor() default {};
 
  String[] noRollbackForClassName() default {};
}

@Transactional注解的几个属性

propagation

事务的传播机制,主要有以下几种,默认是REQUIRED:

  1. REQUIRED - 方法A调用时候没有事务新建一个事务,在方法A中调用方法B,将使用相同的事务,如果方法B发生异常需要回滚,整个事务回滚。
  2. REQUIRES_NEW - 方法A调用方法B时,无论是否存在事务都开启一个新事务,这样B方法异常不会导致A的数据回滚。
  3. NESTED - 和REQUIRES_NEW类似,但是只支持JDBC,不支持JPA或Hibernate
  4. SUPPORTS - 方法调用时有事务就用事务,没事务就不用事务
  5. NOT_SUPPORTED - 强制方法不在事务中执行,若有事务,在方法调用到结束阶段先挂起事务。
  6. NEVER - 强制不能有事务,若有事务就抛出异常
  7. MANDATORY - 强制必须有事务,如果没有事务就抛出异常

isolation

事务的隔离级别,决定了事务的完整性,主要一下几种,默认是DEFAULT:

  1. READ_UNCOMMITTED - A事务修改记录但没提交,B事务可读取到修改后的值。可导致脏读、不可重复读、幻读。
  2. READ_COMMITTED - A事务修改并提交后,B事务才能读取到修改后的值,阻止了脏读,但可能导致不可重复读和幻读。
  3. REPEATABLE_READ - A事务读取了一条记录,B事务将不能修改这条记录,阻止脏读和不可重复读,但是可能出现幻读。
  4. SERIALIZABLE - 事务是顺序执行的,可避免所有缺陷,但是开销很大。
  5. DEFAULT - 使用当前数据库默认隔离级别,入Oracle、SQL Server是READ_COMMITTED,MySQL是REPEATABLE_READ

timeout

事务过期时间,默认是当前数据库默认事务过期时间。

readOnly

指定是否为只读事务,默认是false

如果你一次执行单条查询语句,则没有必要启用事务支持,数据库默认支持SQL执行期间的读一致性;

如果你一次执行多条查询语句,例如统计查询,报表查询,在这种场景下,多条查询SQL必须保证整体的读一致性, 否则,在前条SQL查询之后,后条SQL查询之前,数据被其他用户改变,则该次整体的统计查询将会出现读数据不一致的状态, 此时,应该启用只读事务支持。

只读事务与读写事务区别:

对于只读查询,可以指定事务类型为readonly,即只读事务。由于只读事务不存在数据的修改, 因此数据库将会为只读事务提供一些优化手段,例如Oracle对于只读事务,不启动回滚段,不记录回滚log。

rollbackFor

指定哪些异常可以导致事务回滚,默认是Throwable的子类

noRollbackFor

执行哪些异常不可用引起事务回滚,默认是Throwable的子类

2、springboot事务使用

Spring boot是默认启动事务的,只需要在类或者方法上添加@Transactional注解即可,但有时候会发现事务不生效,具体原因可以从以下几个方面找寻:

1、首先要看数据库引擎是否支持注解,mysql默认引擎INNODB是支持的,但MYISAM是不支持的;

2、注解只能被应用到public方法上, 其它方法上不会报错,但不生效;

3、默认情况下只会对运行期异常(java.lang.RuntimeException及其子类)和 Error 进行回滚;

4、如果是其它异常,可以显形标记在参数里,下图标红的就是先进行查看用户有指定的异常,如果没有,就默认上一条的异常,参数格式:@Transactional(rollbackFor={Exception.class})

5、是否进行了异常捕获,如果使用了try--catch,事务是肯定不生效,也就是系统没有接收到异常场景;

关于使用异常捕获,还想事务生效,可以有几种策略解决相关难题:

   1)手动回滚,推荐方式

2)在catch里抛出一个runntimeException

3)  将异常写入注解参数里面,也需要抛出来,原理跟方法2一样的,只是重新指定了事务回滚的异常类型

二、全局事务

采用Aop对项目进行全局异常事务处理

@Aspect
@Configuration
public class TransactionAdviceConfig {
  
  private static final String AOP_POINTCUT_EXPRESSION = "execution(* demo.service.impl.*.*(..))";
 
  @Autowired
  private PlatformTransactionManager transactionManager;
 
  @Bean
  public TransactionInterceptor txAdvice() {
 
    DefaultTransactionAttribute txAttr_REQUIRED = new DefaultTransactionAttribute();
    txAttr_REQUIRED.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
 
    DefaultTransactionAttribute txAttr_REQUIRED_READONLY = new DefaultTransactionAttribute();
    txAttr_REQUIRED_READONLY.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
    txAttr_REQUIRED_READONLY.setReadOnly(true);
 
    NameMatchTransactionAttributeSource source = new NameMatchTransactionAttributeSource();
    source.addTransactionalMethod("add*", txAttr_REQUIRED);
    source.addTransactionalMethod("delete*", txAttr_REQUIRED);
    source.addTransactionalMethod("update*", txAttr_REQUIRED);
    source.addTransactionalMethod("select*", txAttr_REQUIRED_READONLY);
    source.addTransactionalMethod("likeSelect*", txAttr_REQUIRED_READONLY);
    return new TransactionInterceptor(transactionManager, source);
  }
 
  @Bean
  public Advisor txAdviceAdvisor() {
    AspectJExpressionPointcut pointcut = new AspectJExpressionPointcut();
    pointcut.setExpression(AOP_POINTCUT_EXPRESSION);
    return new DefaultPointcutAdvisor(pointcut, txAdvice());
  }
}

三、扩展

隔离级别

传播行为


相关文章
|
3月前
|
安全 Java easyexcel
【二十七】springboot实现多线程事务处理
【二十七】springboot实现多线程事务处理
243 0
|
3月前
|
JavaScript Java 测试技术
基于SpringBoot+Vue+uniapp的学生事务处理系统的详细设计和实现(源码+lw+部署文档+讲解等)
基于SpringBoot+Vue+uniapp的学生事务处理系统的详细设计和实现(源码+lw+部署文档+讲解等)
|
Java 数据库连接 计算机视觉
SpringBoot 中的多线程事务处理太繁琐?一个自定义注解直接搞定!
SpringBoot 中的多线程事务处理太繁琐?一个自定义注解直接搞定!
|
Oracle NoSQL Java
SpringBoot | 1.4 数据库事务处理
前面讲解了Sring的AOP,可以知道它是用来抽取公共代码,增强方法的。而在JDBC操作数据库进行数据处理时,有很多重复的公共代码;事务的提交与回滚跟AOP的约定流程很相似。因此,Spring数据库事务编程的思想基于AOP的设计思想,数据库事务处理是AOP的一种典型应用。 注:在说明注解时,第一点加粗为注解中文含义,第二点为一般加在哪身上,缩进或代码块为示例,如: **@注解** - **中文含义** - 加在哪 - 其他…… - `语句示例` ```java //代码示例 ```
623 0
SpringBoot | 1.4 数据库事务处理
|
5天前
|
SQL JavaScript 前端开发
vue中使用分页组件、将从数据库中查询出来的数据分页展示(前后端分离SpringBoot+Vue)
这篇文章详细介绍了如何在Vue.js中使用分页组件展示从数据库查询出来的数据,包括前端Vue页面的表格和分页组件代码,以及后端SpringBoot的控制层和SQL查询语句。
vue中使用分页组件、将从数据库中查询出来的数据分页展示(前后端分离SpringBoot+Vue)
|
22小时前
|
JavaScript Java Maven
毕设项目&课程设计&毕设项目:springboot+vue实现的在线求职管理平台(含教程&源码&数据库数据)
本文介绍了一款基于Spring Boot和Vue.js实现的在线求职平台。该平台采用了前后端分离的架构,使用Spring Boot作为后端服务
毕设项目&课程设计&毕设项目:springboot+vue实现的在线求职管理平台(含教程&源码&数据库数据)
|
1天前
|
Java 微服务 Spring
SpringBoot+Vue+Spring Cloud Alibaba 实现大型电商系统【分布式微服务实现】
文章介绍了如何利用Spring Cloud Alibaba快速构建大型电商系统的分布式微服务,包括服务限流降级等主要功能的实现,并通过注解和配置简化了Spring Cloud应用的接入和搭建过程。
SpringBoot+Vue+Spring Cloud Alibaba 实现大型电商系统【分布式微服务实现】
|
1天前
|
NoSQL JavaScript 前端开发
SpringBoot+Vue实现校园二手系统。前后端分离技术【完整功能介绍+实现详情+源码】
文章介绍了如何使用SpringBoot和Vue实现一个校园二手系统,采用前后端分离技术。系统具备完整的功能,包括客户端和管理员端的界面设计、个人信息管理、商品浏览和交易、订单处理、公告发布等。技术栈包括Vue框架、ElementUI、SpringBoot、Mybatis-plus和Redis。文章还提供了部分源代码,展示了前后端的请求接口和Redis验证码功能实现,以及系统重构和模块化设计的一些思考。
SpringBoot+Vue实现校园二手系统。前后端分离技术【完整功能介绍+实现详情+源码】
|
4天前
|
前端开发 JavaScript Java
SpringBoot+Vue+token实现(表单+图片)上传、图片地址保存到数据库。上传图片保存位置自己定义、图片可以在前端回显(一))
这篇文章详细介绍了在SpringBoot+Vue项目中实现表单和图片上传的完整流程,包括前端上传、后端接口处理、数据库保存图片路径,以及前端图片回显的方法,同时探讨了图片资源映射、token验证、过滤器配置等相关问题。