【Spring】5.Spring事务中的@Transactional注解剖析

server/2024/10/18 22:32:30/

事务是确保数据完整性的关键机制。Spring框架通过@Transactional注解提供了一种声明式事务管理的方式,极大地简化了事务的使用。在本篇文章中,我们将深入探讨Spring的@Transactional注解,包括它的工作原理、可用属性、如何配置以及在嵌套事务场景下的应用。此外,我们还将讨论将@Transactional注解应用于类与方法时的异同,以及如何选择适当的使用方式。

Spring的@Transactional注解

Spring的@Transactional是一个用于声明方法或类级别的事务属性的注解。它告诉Spring框架,被注解的方法应该在一个事务的上下文中执行。如果方法在事务中执行,那么该方法对数据库所做的更改要么全部成功提交,要么在发生异常时全部撤销。

工作原理

  1. 代理机制:Spring使用AOP(面向切面编程)来实现@Transactional注解。当Spring容器启动时,它扫描所有的@Transactional注解,并为被注解的方法创建一个代理。对于类级别的注解,类中的所有方法都会创建代理。

  2. 事务的创建和结束:当代理方法被调用时,Spring首先检查是否存在一个活动的事务。如果存在,代理方法会加入到这个事务中。如果不存在,Spring会创建一个新的事务。一旦方法执行完成,如果没有异常抛出,事务将被提交;如果发生异常,事务将被回滚。

  3. 事务管理器:Spring使用事务管理器(如DataSourceTransactionManagerJpaTransactionManager)来实际控制事务的创建、提交和回滚。

属性及配置

  1. propagation:定义事务的传播行为。

    • REQUIRED:默认值,加入已存在的事务或创建新事务。
    • SUPPORTS:支持事务但不是必须的;如果没有事务,就以非事务方式执行。
    • MANDATORY:必须在一个事务中执行,否则抛出异常。
    • REQUIRES_NEW:总是创建新事务,并将任何存在的事务挂起。
    • NOT_SUPPORTED:以非事务方式执行,任何存在的事务都会被挂起。
    • NEVER:必须不在事务中执行,如果存在事务则抛出异常。
    • NESTED:如果支持,则创建一个嵌套事务。
    java">@Transactional(propagation = Propagation.REQUIRES_NEW)
    
  2. isolation:定义事务的隔离级别。

    • DEFAULT:使用后端数据库的默认隔离级别。
    • READ_UNCOMMITTED:最低隔离级别,允许读取未提交的数据。
    • READ_COMMITTED:保证读取已提交的数据。
    • REPEATABLE_READ:保证在一个事务中看到的数据保持不变。
    • SERIALIZABLE:最高隔离级别,完全串行化的事务。
    java">@Transactional(isolation = Isolation.READ_COMMITTED)
    
  3. timeout:定义事务的超时时间(秒)。如果事务在这个时间内没有完成,它将被自动回滚。

    java">@Transactional(timeout = 30)
    
  4. readOnly:指定事务是否为只读事务。这可以给数据库一个优化的提示。

    java">@Transactional(readOnly = true)
    
  5. rollbackFor:定义哪些异常类型会导致事务回滚。可以指定一个异常类型数组。

    java">@Transactional(rollbackFor = {RuntimeException.class, CustomException.class})
    
  6. noRollbackFor:定义哪些异常类型不会导致事务回滚。可以指定一个异常类型数组。

    java">@Transactional(noRollbackFor = NoRollbackException.class)
    
  7. phase:定义在事务的哪个阶段应用事务管理。通常与基于方法的事务管理相关。

    java">@Transactional(phase = TransactionPhase.BEFORE_COMMIT)
    
  8. transactionManager:指定使用的事务管理器的Bean名称。

    java">@Transactional(transactionManager = "transactionManagerBeanName")
    

通过合理配置这些属性,可以精确控制事务的行为,满足业务需求。

处理嵌套事务

嵌套事务通常在以下情况下需要进行处理:

  1. 细粒度控制:当您希望在一个大的事务中包含一些小的事务,并且这些小的事务可以独立于大事务进行回滚或提交时。
  2. 复杂业务逻辑:在一些复杂的业务逻辑中,可能需要在一个事务中执行多个步骤,其中某些步骤需要独立的事务控制。
  3. 性能优化:在某些情况下,使用嵌套事务可以减少锁争用,从而提高性能。

在Spring Boot中,处理嵌套事务需要使用支持嵌套事务的事务管理器。由于Spring Boot默认的DataSourceTransactionManager不支持嵌套事务,因此通常需要使用JTA事务管理器,如AtomikosBitronix

以下是在Spring Boot中使用@Transactional注解处理嵌套事务的步骤和示例代码:

1. 添加JTA事务管理器依赖

首先,需要添加JTA事务管理器的依赖。以Atomikos为例:

<!-- pom.xml -->
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-jta-atomikos</artifactId>
</dependency>

2. 配置JTA事务管理器

application.propertiesapplication.yml中配置JTA事务管理器:

# application.properties
spring.jta.enabled=true
spring.jta.log-dir=path/to/log/dir

3. 使用@Transactional注解处理嵌套事务

在服务层中,使用@Transactional注解声明外部事务和嵌套事务:

java">@Service
public class BusinessService {@Autowiredprivate NestedService nestedService;@Transactionalpublic void performBusinessOperation() {// 执行一些操作nestedService.performNestedOperation();}
}@Service
public class NestedService {@Transactional(propagation = Propagation.NESTED, readOnly = true)public void performNestedOperation() {// 执行一些只读操作,这些操作在一个嵌套事务中}@Transactional(propagation = Propagation.NESTED, readOnly = false)public void performNestedOperationWithChange() {// 执行一些需要更改数据库的操作// 这些操作在一个嵌套事务中}
}

在这个例子中,BusinessService中的performBusinessOperation方法定义了一个外部事务。当调用NestedService中的performNestedOperationperformNestedOperationWithChange方法时,它们作为一个嵌套事务执行,因为它们也被@Transactional注解,且propagation属性设置为NESTED

注意事项:

  • 确保你的数据库和事务管理器都支持嵌套事务。
  • 使用嵌套事务可能会使事务管理逻辑变得复杂,因此应该谨慎使用。
  • 在使用JTA事务管理器时,可能需要对数据源进行额外的配置,以确保它们能够与JTA事务管理器协同工作。

@Transactional用于类或方法异同

在Spring框架中,@Transactional 注解可以用于类或方法,它们在事务管理上有不同的作用范围和含义:

类级别的 @Transactional

  • @Transactional 注解应用于整个类时,类中的所有公共方法都会继承这个注解的事务属性。
  • 这意味着,除非在单个方法上指定了不同的事务属性,否则类中所有公共方法都会按照类级别注解定义的事务属性执行。
  • 类级别的事务定义提供了一种方便的方式,当一个类中的多个方法共享相同的事务需求时,可以避免在每个方法上重复使用注解。
java">@Transactional(readOnly = true)
public class MyService {public void methodOne() {// ...}public void methodTwo() {// ...}
}

在这个例子中,MyService 类的 methodOnemethodTwo 都将以只读事务执行。

方法级别的 @Transactional

  • 方法级别的@Transactional 注解允许你对单个方法进行特定的事务配置,这会覆盖类级别的定义。
  • 这在需要对类中不同方法应用不同事务属性时非常有用。
  • 方法级别的注解提供了更细粒度的事务控制。
java">public class MyService {@Transactional(readOnly = true)public void readOnlyMethod() {// ...}@Transactional(readOnly = false, propagation = Propagation.REQUIRES_NEW)public void writeMethod() {// ...}
}

在这个例子中,readOnlyMethod 将作为一个只读事务执行,而 writeMethod 将作为一个全新的写事务执行,即使 MyService 类上有类级别的@Transactional注解。

区别和使用场景:

  • 作用范围:类级别的注解影响该类的所有公共方法,而方法级别的注解只影响单个方法。
  • 事务属性:方法级别的注解可以覆盖类级别的注解定义的事务属性。
  • 使用场景:当你需要为类中的多个方法定义统一的事务行为时,可以使用类级别的注解。当你需要为类中的特定方法定义不同的事务行为时,应使用方法级别的注解。

选择使用类级别还是方法级别的@Transactional注解,应基于你的具体需求和事务管理策略。通常,如果多个方法共享相同的事务配置,类级别的注解会更加方便;而当需要对单个方法进行特殊处理时,方法级别的注解则更加灵活。

总结

在本文中,全面介绍了Spring框架中的@Transactional注解,它是实现声明式事务管理的核心工具。该注解能够自动为方法创建事务代理,通过定义不同的事务属性如传播行为、隔离级别、超时时间等,来精确控制事务的开始、提交或回滚。
特别地,讨论了嵌套事务的概念,它允许在现有事务中创建新的事务,这在处理复杂业务逻辑时非常有用。
此外,我们区分了将@Transactional注解应用于类与方法的不同影响,类级别的注解为所有公共方法提供了统一的事务语义,而方法级别的注解则允许更细粒度的事务控制。最后,我们强调了在使用嵌套事务和@Transactional注解时应注意的一些关键点,包括确保事务管理器和数据库的支持,以及对事务配置的谨慎选择。通过这些深入的讨论,我们希望帮助开发者更好地利用Spring的事务管理功能,以提升应用程序的数据处理能力和事务安全性。


http://www.ppmy.cn/server/28025.html

相关文章

Istio基础知识

一、什么是Istio Istio 提供⼀种简单的⽅式来为已部署的服务建⽴⽹络&#xff0c;该⽹络具有 负载均衡、服务间认证、监控等功能&#xff0c;只需要对服务的代码进⾏⼀点或不需要做任何改动。想要让服务⽀持 Istio&#xff0c;只需要在您的环境中部署⼀个特殊的 sidecar 代 理&…

笨蛋学C++之 C++对数据库实现CRUD

笨蛋学C 之 C对数据库实现CRUD 头文件testcrud.h 源文件testcrud.cppmain.cpp 头文件 testcrud.h #pragma once #include <mysql.h> #include <iostream> #include <vector> #include <cstring> // 包含字符串操作相关的头文件 using namespace std;…

【华为】华为防火墙双机热备

【华为】华为防火墙双机热备 实验需求实验拓扑配置FW5-M前骤单臂路由和VRRP划分防火墙基本区域部署HRP&#xff08;华为心跳协议&#xff09; FW6-B前骤单臂路由和VRRP划分防火墙基本区域部署HRP&#xff08;华为心跳协议&#xff09; LSW2PC NATSNAT &#xff1a;Easy IPDNAT&…

【Docker】搭建一个媒体服务器插件后端API服务 - MetaTube

【Docker】搭建一个媒体服务器插件后端API服务 - MetaTube 前言 本教程基于群晖的NAS设备DS423的docker功能进行搭建&#xff0c;DSM版为 7.2.1-69057 Update 5。 简介 MetaTube 是一个媒体服务器插件&#xff0c;主要用于 Emby 和 Jellyfin 媒体服务器。它的主要功能是从互…

Typora+PicGo+阿里云OSS搭建个人博客图床(2024最新详细搭建教程)

创作者&#xff1a;Code_流苏(CSDN) 目录 一、什么是图床&#xff1f;二、准备工作三、配置PicGo四、配置Typora五、使用 很高兴你打开了这篇博客&#xff0c;如有疑问&#xff0c;欢迎评论。 更多好用的软件工具&#xff0c;请关注我&#xff0c;订阅专栏《实用软件与高效工具…

路由器的构成

一、路由器简介 路由器是互联网中的关键设备&#xff1a; 连接不同的网络路由器是多个输入端口和多个输出端口的专用计算机&#xff0c;其任务是转发分组&#xff08;转发给下一跳路由器&#xff09;下一跳路由器也按照这种方法处理分组&#xff0c;直到该分组到达终点为止 …

LeetCode 198—— 打家劫舍

阅读目录 1. 题目2. 解题思路3. 代码实现 1. 题目 2. 解题思路 此题使用动态规划求解&#xff0c;假设 d p [ i ] [ 0 ] dp[i][0] dp[i][0] 代表不偷窃第 i i i 个房屋可以获得的最高金额&#xff0c;而 d p [ i ] [ 1 ] dp[i][1] dp[i][1] 代表偷窃第 i i i 个房屋可以获…

Blender常见操作

1.局部视图&#xff1a;Local View&#xff0c;也可称作Solo模式&#xff0c;按快捷键 “/”进入&#xff0c;在按退出&#xff0c;只显示选中的物体&#xff08;可多选&#xff09;&#xff0c;方便编辑 2.物体合并&#xff1a;Ctrl J 其中&#xff0c;当选中多个物体时&am…