基于Spring中的事务@Transactional细节与易错点、幻读

让我们来详细讲解基于Spring中的事务 @Transactional 细节与易错点、幻读的完整攻略。

什么是事务?

事务是一组操作,这些操作要么全部执行成功,要么全部不执行。如果其中任何一项操作失败,事务会回滚到开始状态,以确保数据在数据库中的完整性。

Spring中的事务管理

Spring是一个开发框架,也提供了很好的事务管理。Spring的事务管理可以统一管理不同类型的事务,无论是JDBC的事务,还是一些支持JTA的应用服务器的事务。 Spring中的事务管理主要由两个重要的接口组成:TransactionManagerPlatformTransactionManager,其中 PlatformTransactionManager 是用来针对具体的持久化技术,向上对接了 TransactionManager。在实践中,我们主要通过配置 DataSourceTransactionManagerJpaTransactionManager 等具体实现类去进行具体的事务管理。

事务的属性配置

@Transactional 常用的属性有 propagationisolationtimeoutreadOnlyrollbackFor 等。

propagation

事务传播行为的属性有 REQUIREDREQUIRES_NEWSUPPORTSNOT_SUPPORTEDNEVERMANDATORYNESTED

通过 REQUIRED 标签指示方法需要事务支持,如果当前上下文中已经有事务了,那么它在当前事务中运行;否则,它将创建一个新的事务。下面的代码演示了 REQUIRED 行为标签的用法:

@Transactional(propagation = Propagation.REQUIRED)

isolation

隔离级别是用来处理并发事务执行所引起的问题,比如脏读、不可重复读、幻读。

常用的隔离级别包括 READ_COMMITTEDREAD_UNCOMMITTEDREPEATABLE_READSERIALIZABLE,其中 READ_COMMITTED 级别是最常用的,默认级别。

下面的代码演示了隔离级别的用法:

@Transactional(isolation = Isolation.REPEATABLE_READ)

timeout

timeout 属性指定了事务的超时时间。超时就会抛出异常,回滚事务。

下面的代码演示了超时时间 5 秒的用法:

@Transactional(timeout=5)

readOnly

readOnly 属性说明当前事务是否只读。如果只读,那么不允许事务在执行期间修改任何数据。

下面的代码演示了 readOnly 属性的实现:

@Transactional(readOnly = true)
public List<Customer> listCustomers() {
    return customerDao.findAll();
}

rollbackFor

默认情况下, Spring 事务只有在出现 Runtime 异常才回滚,在出现其他类型异常时不回滚。通过 rollbackFor 属性显式设置一些异常,可以实现在遇到这些异常时回滚事务。下面的代码演示了回滚指定异常的用法:

@Transactional(rollbackFor = {Exception.class})
public void save(Customer customer) throws Exception {
    // do something
}

常见易错点

非 Runtime 异常导致事务不回滚

事务默认只回滚 RuntimeException 异常,对于 Exception 异常不会自动回滚,因此如果你写了一个抛出 Exception 的异常,事务将不会自动回滚。需要在 @TransactionalrollbackFor 中声明,例如:

@Transactional(rollbackFor = Exception.class)

异常被吃掉导致事务不回滚

当某个异常没有被正确的抛出,甚至被吃掉了,事务也会失效。

比如在以下的代码中,由于异常被 try-catch 了,导致事务不会回滚:

@Transactional
public void test() {
    try {
        // do something
    } catch (Exception e) {
        // 异常被捕获
    }
}

外部调用类、方法没有加事务注解,导致事务失效

Spring 的事务管理针对 @Transactional 的注解才会生效,如果被调用方法所在的类没有加上事务注解,事务会失效。例如:

@Transactional
public class UserService {
    public void saveUser() {
        // do something
    }
}

public class UserController {
    private UserService userService;
    public void saveUser() {
        userService.saveUser();
    }
}

在这段代码中,UserController 调用 UserServicesaveUser() 方法,由于 UserService 类没有使用事务注解,事务不会生效。

幻读问题

幻读问题出现的原因是在并发情况下事务只锁住语句执行的数据行,而没有锁定数据页,因此其他事务可以在数据页中插入数据。这样就导致了在读取数据的时候,出现了虚假的行的情况,就好像魔幻般出现了新的行。

以下是一个处理幻读问题的示例:

@Transactional(isolation = Isolation.REPEATABLE_READ)
public void handlePhantomRead() {
    // Step 1: 查询一次结果集
    List<Customer> customers = customerDao.findCustomersByAddress("xxx");
    // Step 2: 其他事务新增数据
    customerDao.insertCustomer(new Customer("xxx", "male", 30));
    // Step 3: 再次查询,导致出现幻读
    List<Customer> customers2 = customerDao.findCustomersByAddress("xxx");
}

以上代码中的第二步插入数据的操作,会在第一步查询数据之后被执行,从而导致第三步查询出现了幻读。要避免幻读,可以在查询前先执行 SELECT … FOR UPDATE 操作来加锁:

@Transactional(isolation = Isolation.REPEATABLE_READ)
public void handlePhantomRead() {
    // Step 1: 查询一次结果集,并且在查询前先执行 SELECT … FOR UPDATE 操作来加锁
    List<Customer> customers = customerDao.findCustomersByAddressForUpdate("xxx");
    // Step 2: 其他事务新增数据
    customerDao.insertCustomer(new Customer("xxx", "male", 30));
    // Step 3: 再次查询,由于在查询时加锁,避免了幻读问题
    List<Customer> customers2 = customerDao.findCustomersByAddress("xxx");
}

以上便是基于Spring中的事务 @Transactional 细节与易错点、幻读的完整攻略,希望对你有所帮助。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:基于Spring中的事务@Transactional细节与易错点、幻读 - Python技术站

(0)
上一篇 2023年5月18日
下一篇 2023年5月18日

相关文章

  • MySQL冷备份所需物理文件

    MySQL冷备份是一种备份方式,它的特点是备份过程中数据库不会被访问或修改。这种备份方式可以在数据库运行期间进行,不会对正常业务产生影响,并且备份文件的大小、恢复速度、稳定性都比较好。 在进行MySQL冷备份时,需要备份一些物理文件。 数据库文件 MySQL的数据库文件通常存储在数据目录下,这些文件包括数据文件(.frm、.ibd等)和日志文件(.ib_lo…

    MySQL 2023年3月10日
    00
  • 查询Oracle中正在执行和执行过的SQL语句

    要查询Oracle数据库中正在执行和执行过的SQL语句,可以进行以下步骤: 步骤1:开启SQL跟踪 在Oracle数据库中,SQL跟踪是一种捕捉SQL执行信息的机制,它可以记录SQL语句的执行时间、执行计划、I/O等信息。要查询数据库中正在执行和执行过的SQL语句,需要先开启SQL跟踪。可以通过以下命令开启SQL跟踪: ALTER SESSION SET S…

    database 2023年5月21日
    00
  • docker安装mysql,设置mysql初始密码

    docker安装mysql,只需要2分钟就可以完成 docker search mysql 拉取mysql镜像(https://hub.docker.com/_/mysql) docker pull mysql:5.7 官网可查看存在的镜像,以及需要的版本号 运行mysql(–name 容器名称  -e MYSQL_ROOT_PASSWORD设置初始密码 …

    MySQL 2023年4月12日
    00
  • Community Server专题一:概述Community Server

    Community Server专题一:概述Community Server Community Server是一个开放源代码的社区论坛系统,可以让任何人轻松地创建和管理一个社区论坛网站。它的核心功能包括讨论区、文章列表、个人资料、私人消息、通知、标签和分类等。在这篇文章中,我们将会详细讲解Community Server的功能和用途,以及如何创建和配置一个…

    database 2023年5月21日
    00
  • SQL注入是什么?SQL注入原理及预防方法

    SQL注入是一种针对Web应用程序的攻击方法,攻击者通过注入恶意的SQL语句来获取或修改数据库中的数据。攻击者可以利用各种SQL注入技术来执行操作,包括数据盗取、数据修改和数据删除等。 SQL注入是利用了应用程序对用户输入数据的不充分验证,把恶意的SQL代码注入到应用程序的查询语句中,通过这种方式来控制或者破坏数据库的行为 SQL注入攻击是Web应用程序最常…

    MySQL 2023年3月10日
    00
  • MySQL创建表操作命令分享

    MySQL是一款常用的数据库管理系统,用于存储和管理数据。创建表是MySQL数据库中的一个重要的基本操作。在此,我将分享MySQL创建表操作命令的完整攻略,包括必要的语法和示例。 语法 创建MySQL表的语法如下所示: CREATE TABLE table_name ( column1 datatype constraints, column2 dataty…

    database 2023年5月22日
    00
  • MySQL 声明变量及存储过程分析

    MySQL 声明变量及存储过程是一个比较常用的操作,能够使我们更加高效地操作数据库。下面将为您介绍声明变量和存储过程的操作步骤及示例代码。 声明变量 MySQL 声明变量的语句格式为:SET @var_name = value;。其中 @var_name 为变量名,value 为变量的值。 示例一:声明变量并赋值 SET @user_id = 1; SELE…

    database 2023年5月22日
    00
  • 类Linux环境安装jdk1.8及环境变量配置详解

    类Linux环境安装jdk1.8及环境变量配置详解 简介 本文介绍如何在类Linux环境(比如CentOS、Ubuntu等)下安装jdk1.8并配置环境变量的详细过程。 本文的安装环境为CentOS 7.6。 步骤 下载JDK1.8 在Oracle官网上下载JDK1.8的Linux版本(tar.gz压缩包),下载地址为:https://www.oracle.…

    database 2023年5月22日
    00
合作推广
合作推广
分享本页
返回顶部