springboot事务详解

阅读数:115 评论数:0

跳转到新版页面

分类

python/Java

正文

一、概述

1、事务

事务就是一组操作数据库的动作集合,集合中的动作要么全部执行,要么全部不执行。

2、事务特点(ACID)

Atomicity 原子性 整个事务是一个整体,是不可分割的最小工作单位。一个事务中的所有操作要么全部执行成功,要么全部都不执行,其中任何一条操作失败,都会导致事务回滚
Consistency一致性 数据的记录总是从一个一致状态转变成另一个致性状态。
Isolation 隔离性 一个事务的执行,不受其它事务的干扰,即并发执行的事务之间互不干扰
Duration 持久性 数据一旦提交,结果就是永久性的,并不应为宕机等情况丢失。

二、事务的实现方式

1、mysql事务的实现方式

(1)原子性和持久性利用redo log(重做日志)实现。

(2)一致性利用undo log(回滚日志)实现。

(3)隔离性利用锁来实现。

(4)innodb引擎支持事务,myisam不支持事务

2、springboot实现的方式

spring事务管理分为编码式和声明式两种:

(1)编码式

使用TransactionTemplate或者直接使用底层的PlatformTransactionManager。

PlatformTransactionManager接口中定义了创建、提交和回滚事务的方法:

@Autowired
DataSourceTransactionManager dataSourceTransactionManager;
@Autowired
TransactionDefinition transactionDefinition;
 
// 手动创建事务
TransactionStatus transactionStatus = dataSourceTransactionManager.getTransaction(transactionDefinition);
 
// 手动提交事务
dataSourceTransactionManager.commit(transactionStatus);
 
// 手动回滚事务。(最好是放在catch 里面,防止程序异常而事务一直卡在哪里未提交)
dataSourceTransactionManager.rollback(transactionStatus);

常用的实现类比如DataSourceTransactionalManager,它对应的是传统的JDBC事务管理。

(2)声明式:基于AOP

对方法前后进行拦截,在目标方法之前创建或者加入一个事务,方法执行之后根据执行情况提交或回滚事务。声明式事务有两种方式,一种是在配置文件中做相关的事务规则声明,另一种是基于@Transaction注解的方式。

三、@Transactional注解

1、使用注意事项

(1)在具体的类(或类的方法)上使用@Transactional注解,而不要使用在类所要实现的任何接口上。

(2)只能被应用在public修饰的方法上。

(3)基于动态代理,需要一个类调用另一个类,类内调用会失效。

(4)假设被外部调用的公共方法A有两个进行数据操作的方法B和方法C:

A声明了事务 正常运行,事务由A控制
A未声明事务 B和C是其它类的方法,且各种声明事务,事务由B和C各种控制
B和C是本类的方法,不论B和C是否声明事务,事务都不会生效

(5)如果自已使用的try-catch捕获异常,则回滚不会执行,如果需要try-catch后仍回滚,需要

//手动抛出异常
try{
      ....  
  }catch(Exception e){
      logger.error("fail",e);
      throw new RuntimeException;
}

// 或者手动回滚

try{
      ...
  }catch(Exception e){
      log.error("fail",e);
      TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
      return false;
}

2、常用配置

参 数 名 称 功 能 描 述
readOnly 该属性用于设置当前事务是否为只读事务,设置为true表示只读,false则表示可读写,默认值为false。例如:@Transactional(readOnly=true)
rollbackFor rollbackFor 该属性用于设置需要进行回滚的异常类数组,当方法中抛出指定异常数组中的异常时,则进行事务回滚。例如:指定单一异常类:@Transactional(rollbackFor=RuntimeException.class)指定多个异常类:@Transactional(rollbackFor={RuntimeException.class,Exception.class})
rollbackForClassName 该属性用于设置需要进行回滚的异常类名称数组,当方法中抛出指定异常名称数组中的异常时,则进行事务回滚。例如:指定单一异常类名称@Transactional(rollbackForClassName="RuntimeException")指定多个异常类名称:@Transactional(rollbackForClassName={"RuntimeException","Exception"})
noRollbackFor 该属性用于设置不需要进行回滚的异常类数组,当方法中抛出指定异常数组中的异常时,不进行事务回滚。例如:指定单一异常类:@Transactional(noRollbackFor=RuntimeException.class)指定多个异常类:@Transactional(noRollbackFor={RuntimeException.class, Exception.class})
noRollbackForClassName 该属性用于设置不需要进行回滚的异常类名称数组,当方法中抛出指定异常名称数组中的异常时,不进行事务回滚。例如:指定单一异常类名称:@Transactional(noRollbackForClassName="RuntimeException")指定多个异常类名称:@Transactional(noRollbackForClassName={"RuntimeException", "Exception"})
propagation 该属性用于设置事务的传播行为。例如:@Transactional(propagation=Propagation.NOT_SUPPORTED, readOnly=true)
isolation 该属性用于设置底层数据库的事务隔离级别,事务隔离级别用于处理多事务并发的情况,通常使用数据库的默认隔离级别即可,基本不需要进行设置
timeout 该属性用于设置事务的超时秒数,默认值为-1表示永不超时 事物超时设置:@Transactional(timeout=30) ,设置为30秒

(1)默认情况下,Spring会对unchecked异常进行事务回滚,也就是默认对RuntimeException异常或者其子类进行事务回滚;如果是checked异常则不会回滚。

例如空指针异常、算数异常都会回滚;但文件读写、网络等异常,则不会回滚。所以若想对所有异常都起作用,需要:

@Transactional(rollbackFor = Exception.class)

3、事务传播行为

Spring在TranscationDefinition接口中规定了7种类型的事务传播行为,Propagation枚举引用了这些类型,开发过程中我们一般直接使用Propagation枚举。

@Transactional(propagation=Propagation.NOT_SUPPORTED,readOnly=true)
事务传播行为类型 说明
PROPAGATION_REQUIRED 需要事务(默认)。若当前无事务,新建一个事务;若当前有事务,加入此事务中
PROPAGATION_SUPPORTS 支持事务。若当前没有事务以非事务方式执行;若当前有事务,加入此事务中
PROPAGATION_MANDATORY 强制使用事务。若当前有事务,就使用当前事务;若当前没有事务,抛出IllegalTransactionStateException异常
PROPAGATION_REQUIRES_NEW 新建事务。无论当前是否有事务,都新建事务运行
PROPAGATION_NOT_SUPPORTED 不支持事务。若当前存在事务,把当前事务挂起,然后运行方法
PROPAGATION_NEVER 不使用事务。若当前方法存在事务,则抛出IllegalTransactionStateException异常,否则继续使用无事务机制运行
PROPAGATION_NESTED 嵌套。如果当前存在事务,则在嵌套事务内执行;如果当前没有事务,则执行与PROPAGATION_REQUIRED类似的操作

4、事务的隔离级别

@Transactional(isolation = Isolation.READ_COMMITTED)
隔离级别 含义
DEFAULT 这是一个PlatfromTransactionManager默认的隔离级别,使用数据库默认的事务隔离级别另外四个与JDBC的隔离级别相对应
READ_UNCOMMITTED 最低的隔离级别。事实上我们不应该称其为隔离级别,因为在事务完成前,其他事务可以看到该事务所修改的数据。而在其他事务提交前,该事务也可以看到其他事务所做的修改。可能导致脏,幻,不可重复读
READ_COMMITTED 大多数数据库的默认级别。在事务完成前,其他事务无法看到该事务所修改的数据。遗憾的是,在该事务提交后,你就可以查看其他事务插入或更新的数据。这意味着在事务的不同点上,如果其他事务修改了数据,你就会看到不同的数据。可防止脏读,但幻读和不可重复读仍可以发生
REPEATABLE_READ ISOLATION_READ_COMMITTED更严格,该隔离级别确保如果在事务中查询了某个数据集,你至少还能再次查询到相同的数据集,即使其他事务修改了所查询的数据。然而如果其他事务插入了新数据,你就可以查询到该新插入的数据。可防止脏读,不可重复读,但幻读仍可能发生
SERIALIZABLE 完全服从ACID的隔离级别,确保不发生脏读、不可重复读和幻影读。这在所有隔离级别中也是最慢的,因为它通常是通过完全锁定当前事务所涉及的数据表来完成的。代价最大、可靠性最高的隔离级别,所有的事务都是按顺序一个接一个地执行。避免所有不安全读取

、常用方式

1、自动回滚(直接抛出异常,不try-catch)

@Override
@Transactional(rollbackFor = Exception.class)
public Object submitOrder() throws Exception {  
     success();  
     //假如exception这个操作数据库的方法会抛出异常,方法success()对数据库的操作会回滚
     exception(); 
     return ApiReturnUtil.success();
}

2、手动回滚

@Override
@Transactional(rollbackFor = Exception.class)
public Object submitOrder (){  
    success();  
    try {  
        exception(); 
     } catch (Exception e) {  
        e.printStackTrace();     
        //手工回滚异常
        TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
        return ApiReturnUtil.error();
     }  
    return ApiReturnUtil.success();
}

3、回滚部分异常

@Override
@Transactional(rollbackFor = Exception.class)
public Object submitOrder (){  
    success();  
    //只回滚以下异常,设置回滚点
    Object savePoint = TransactionAspectSupport.currentTransactionStatus().createSavepoint();
    try {  
        exception(); 
     } catch (Exception e) {  
        e.printStackTrace();     
        //手工回滚异常,回滚到savePoint
        TransactionAspectSupport.currentTransactionStatus().rollbackToSavepoint(savePoint);
        return ApiReturnUtil.error();
     }  
    return ApiReturnUtil.success();
}



相关推荐

一、request uri部分 @PathVariable 获取路径参数,形如url/{id} 二、request header部分 @RequestHeade

一、问题原因 1、由于Spring事务是通过AOP实现的。 所以在synchronized修饰的方法执行前会有开启事务,之后会有提交事务逻辑。 // 示例性代码 public static void

一、概述 一个项目使用多个数据库(无论是主从复制--读写分离还是分布式数据库结构)的重要性变得越来越明显,整合的多数据源有两种方式:分包和aop。 1、SqlSessionTemplate SqlSe

一、概述 PageHelper是开源免费的mybatis第三方分页插件。 二、使用 1、pom引入 <dependency> <groupId>com.github.pageh

一、日志框架的介绍 Spring Boot 2.*默认采用slf4j+logback的形式,slf4j是个通用的日志门面,logback就是个具体的日志框架了。

一、问题解决方式 @PostMapping("/insert") @ResponseBody private ResultVO insert1(@RequestParam Map<String, St

JJWT 全称Java Json Web Token。 而JWT是一种在两方之间传输信息的方法,在jwt的主体中编码的信息被称为claims。jwt的扩展形式是json,因此每个c

POM依赖 &lt;dependency&gt; &lt;groupId&g

一、概述 @EnableConfigurationProperties注解的作用是:让使用了@ConfigurationProperties注解的类生效,并且将该类注入到IOC容器中,交由IOC容器进

一、概述 Druid(德鲁伊)是Java语言中的数据库连接池,Spring Boot 2.x默认使用Hikari数据源,虽然HikariCP的速度稍快,但是,Druid能够提供强大的监控和扩展功能。