Spring @Transactional事务管理

简介: Spring @Transactional事务管理

事务管理对于企业应用来说是至关重要的,即使出现异常情况,它也可以保证数据的一致性。


1. 事务的定义


事务: 是数据库操作的最小工作单元,是作为单个逻辑工作单元执行的一系列操作;这些操作作为一个整体一起向系统提交,要么都执行、要么都不执行;事务是一组不可再分割的操作集合(工作逻辑单元)。


2. 事务的四大特性


原子性

事务中的操作为一个整体,要么都做,要么都不做,即一旦事务出错,就回滚事务

一致性

执行的结果必须是使数据库从一个一致性状态变到另一个一致性状态。因此当数据库只包含成功事务提交的结果时,就说数据库处于一致性状态。

如果数据库系统 运行中发生故障,有些事务尚未完成就被迫中断,这些未完成事务对数据库所做的修改有一部分已写入物理数据库,这时数据库就处于一种不正确的状态,或者说是 不一致的状态。

隔离性

一个事务的执行不能被其他事务干扰。即一个事物内部的操作及使用的数据对并发的其他事务是隔离的,并发执行的各个事物之间不能互相干扰。

持久性

指一个事物一旦提交,它对数据库中数据的改变就应该是永久性的。接下来的其他操作或故障不应该对其有任何影响。


3. 事务管理方式


Spring支持 编程式事务管理 和 声明式事务管理 两种方式。


编程式事务Spring推荐使用TransactionTemplate。


声明式事务管理建立在AOP之上 的。其本质是对方法前后进行拦截,然后在目标方法开始之前创建或者加入一个事务,在执行完目标方法之后根据执行情况提交或者回滚事务。声明式事务最大的优点就是不需要通过编程的方式管理事务,这样就不需要在业务逻辑代码中掺杂事务管理的代码,只需在配置文件中做相关的事务规则声明(或通过基于@Transactional注解的方式),便可以将事务规则应用到业务逻辑中。


声明式事务唯一不足地方是只能作用到方法级别,无法做到像编程式事务那样可以作用到代码块级别。


4. @Transactional注解


注解参数如下


- propagation

事务传播类型。默认为 Propagation.REQUIRED

可选值 描述
Propagation.REQUIRED 支持当前事务,如果不存在则创建一个新事务。这是事务注释的默认设置
SUPPORTS 支持当前事务,如果不存在则以非事务方式执行。
MANDATORY 支持当前事务,如果不存在则抛出异常。
REQUIRES_NEW 创建一个新事务,如果存在则暂停当前事务
NOT_SUPPORTED 以非事务方式执行,如果存在则暂停当前事务
NEVER 以非事务方式执行,如果存在事务则抛出异常
NESTED 如果当前事务存在,则在嵌套事务中执行,否则行为类似于 REQUIRED。


- timeout

事务的超时时间(以秒为单位)。默认为底层事务系统的默认超时(30秒)。


- timeoutString

同timeout,此事务的超时时间(以秒为单位)。默认为底层事务系统的默认超时。


- isolation

事务隔离级别。默认为 Isolation.DEFAULT


脏读 : 一个事务读取到另一事务未提交的更新数据

不可重复读 : 在同一事务中, 多次读取同一数据返回的结果有所不同, 换句话说,

后续读取可以读到另一事务已提交的更新数据. 相反, "可重复读"在同一事务中多次

读取数据时, 能够保证所读数据一样, 也就是后续读取不能读到另一事务已提交的更新数据

幻读 : 一个事务读到另一个事务已提交的insert数据

可选值 描述
Isolation.DEFAULT 使用底层数据存储的默认隔离级别。所有其他级别对应于 JDBC 隔离级别。
Isolation.READ_UNCOMMITTED 读取未提交数据(会出现脏读、不可重复读、幻读) 基本不使用
Isolation.READ_COMMITTED 读取已提交数据(会出现不可重复读和幻读)
Isolation.REPEATABLE_READ 可重复读(会出现幻读)
Isolation.SERIALIZABLE最高隔离级别,不允许事务并发执行,而必须串行化执行,最安全,不可能出现更新、脏读、不可重复读、幻读


MYSQL: 默认为REPEATABLE_READ级别

SQLSERVER: 默认为READ_COMMITTED


- readOnly

设置当前事务是否为只读事务,设置为true表示只读,false则表示可读写,默认值为false。


- rollbackFor

设置需要进行回滚的异常类,当方法中抛出指定异常,则进行事务回滚。可以是1个异常活多个异常类,必须是Throwable的子类,默认情况下,事务将在 RuntimeException 和 Error 上回滚。


指定单一异常类:@Transactional(rollbackFor=RuntimeException.class)


指定多个异常类:@Transactional(rollbackFor={RuntimeException.class, Exception.class})


- rollbackForClassName

同上边rollbackFor, 只不过可以是完全限定类名的子字符串,目前不支持通配符。例如,“ServletException”的值将匹配 javax.servlet.ServletException 及其子类。


指定单一异常类名称:@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”})


5. @Transactional不生效的场景


用在非public方法

@Transactional是基于动态代理的,Spring的代理工厂在启动时会扫描所有的类和方法,并检查方法的修饰符是否为public,非public时不会获取@Transactional的属性信息,这时@Transactional的动态代理对象为空。


同一个类中,非@Transactional方法调用@Transactional方法

还是动态代理的原因,类内部方法的调用是通过this调用的,不会使用动态代理对象,事务不会回滚。


异常被捕获

Spring是根据抛出的异常来回滚的,如果异常被捕获了没有抛出的话,事务就不会回滚。


rollbackFor属性设置不对

Spring默认抛出RuntimeException 异常或Error时才会回滚事务,要想其他类型异常也回滚则需要设置rollbackFor属性的值。


当前类没有被Spring管理

没有被Spring管理成为IOC容器中的一个bean,更别说被事务切面代理到了


数据库引擎不支持事务


6. 代码实践


@Transactional 可以作用于接口、接口方法、类以及类方法上。当作用于类上时,该类的所有 public 方法将都具有该类型的事务属性,同时,我们也可以在方法级别使用该标注来覆盖类级别的定义。


虽然 @Transactional 注解可以作用于接口、接口方法、类以及类方法上,但是 Spring 建议不要在接口或者接口方法上使用该注解,因为这只有在使用基于接口的代理时它才会生效。另外, @Transactional 注解应该只被应用到 public 方法上,这是由 Spring AOP 的本质决定的。如果在 protected、private 或者默认可见性的方法上使用 @Transactional 注解,这将被忽略,也不会抛出任何异常。


默认情况下,只有 来自外部的方法调用 才会被AOP代理捕获,也就是,类内部方法调用本类内部的其他方法并不会引起事务行为,即使被调用方法使用@Transactional注解进行修饰。


6.1 声明式事务


@Transactional(readOnly = true)
public class UserServiceImpl implements UserService {
  public void insertAll(List<User> list) {
    // do something
  }
  //方法上注解属性会覆盖类注解上的相同属性
  @Transactional(readOnly = false, propagation = Propagation.REQUIRES_NEW)
  public void updateUser(User user) {
    // do something
  }
}


6.2 编程式事务

@Autowired
private TransactionTemplate transactionTemplate;
@Autowired
private DataSourceTransactionManager dataSourceTransactionManager;
public void insert(){
    // 开启一个只读事务
    transactionTemplate.setReadOnly(true);
    TransactionStatus transactionStatus = dataSourceTransactionManager.getTransaction(transactionTemplate);
    try{
        //do something
        //提交
        dataSourceTransactionManager.commit(transactionStatus);
    }catch(Exception ex){
        //回滚
        dataSourceTransactionManager.rollback(transactionStatus);
    }
}
public void insert2(){
    transactionTemplate.execute(status -> {
        //数据库新增
        dao.insert(2);
        dao.insert(3);
        return new Object();
    });
}
相关文章
|
27天前
|
XML Java 数据库连接
Spring高手之路25——深入解析事务管理的切面本质
本篇文章将带你深入解析Spring事务管理的切面本质,通过AOP手动实现 @Transactional 基本功能,并探讨PlatformTransactionManager的设计和事务拦截器TransactionInterceptor的工作原理,结合时序图详细展示事务管理流程,最后引导分析 @Transactional 的代理机制源码,帮助你全面掌握Spring事务管理。
36 2
Spring高手之路25——深入解析事务管理的切面本质
|
2月前
|
Java Spring 容器
Spring IOC、AOP与事务管理底层原理及源码解析
【10月更文挑战第1天】Spring框架以其强大的控制反转(IOC)和面向切面编程(AOP)功能,成为Java企业级开发中的首选框架。本文将深入探讨Spring IOC和AOP的底层原理,并通过源码解析来揭示其实现机制。同时,我们还将探讨Spring事务管理的核心原理,并给出相应的源码示例。
144 9
|
2月前
|
监控 Java 数据库
Spring事务中的@Transactional注解剖析
通过上述分析,可以看到 `@Transactional`注解在Spring框架中扮演着关键角色,它简化了事务管理的复杂度,让开发者能够更加专注于业务逻辑本身。合理运用并理解其背后的机制,对于构建稳定、高效的Java企业应用至关重要。
71 0
|
3月前
|
Java 数据库连接 数据库
Spring基础3——AOP,事务管理
AOP简介、入门案例、工作流程、切入点表达式、环绕通知、通知获取参数或返回值或异常、事务管理
Spring基础3——AOP,事务管理
|
4月前
|
XML Java 数据库
Spring5入门到实战------15、事务操作---概念--场景---声明式事务管理---事务参数--注解方式---xml方式
这篇文章是Spring5框架的实战教程,详细介绍了事务的概念、ACID特性、事务操作的场景,并通过实际的银行转账示例,演示了Spring框架中声明式事务管理的实现,包括使用注解和XML配置两种方式,以及如何配置事务参数来控制事务的行为。
Spring5入门到实战------15、事务操作---概念--场景---声明式事务管理---事务参数--注解方式---xml方式
|
4月前
|
Java Spring 开发者
掌握Spring事务管理,打造无缝数据交互——实用技巧大公开!
【8月更文挑战第31天】在企业应用开发中,确保数据一致性和完整性至关重要。Spring框架提供了强大的事务管理机制,包括`@Transactional`注解和编程式事务管理,简化了事务处理。本文深入探讨Spring事务管理的基础知识与高级技巧,涵盖隔离级别、传播行为、超时时间等设置,并介绍如何使用`TransactionTemplate`和`PlatformTransactionManager`进行编程式事务管理。通过合理设计事务范围和选择合适的隔离级别,可以显著提高应用的稳定性和性能。掌握这些技巧,有助于开发者更好地应对复杂业务需求,提升应用质量和可靠性。
52 0
|
5月前
|
数据库连接 数据库 开发者
Spring问题之使用@Transactional注解时需要注意哪些事项
Spring问题之使用@Transactional注解时需要注意哪些事项
|
5月前
|
Java 数据库连接 API
Spring事务管理嵌套事务详解 : 同一个类中,一个方法调用另外一个有事务的方法
Spring事务管理嵌套事务详解 : 同一个类中,一个方法调用另外一个有事务的方法
387 1
|
6月前
|
Java 开发者 Spring
深入解析 @Transactional:Spring 事务管理的艺术及实战应对策略
深入解析 @Transactional:Spring 事务管理的艺术及实战应对策略
|
5月前
|
XML Java 关系型数据库
面试一口气说出Spring的声明式事务@Transactional注解的6种失效场景
面试一口气说出Spring的声明式事务@Transactional注解的6种失效场景
133 0