【Spring Boot 事务管理】

Spring Boot 事务管理

一、Spring Boot中的事务管理

1.声明式事务管理

@Transactional注解

Spring最常用的事务管理方式是声明式事务管理,主要通过@Transactional注解实现。这种方式的优点在于简单易用,通过将注解添加到类或方法上,开发者可以轻松地控制事务的边界,而无需直接与底层的事务管理API打交道。

基本使用

在方法级别上使用@Transactional注解,可以确保该方法内的所有操作要么全部成功,要么在遇到异常时全部回滚。

java 复制代码
import org.springframework.transaction.annotation.Transactional;

@Transactional
public void updateUserData(User user) {
    // 这里的数据库操作会在一个事务中执行
}
配置选项

@Transactional注解提供了多种配置选项,包括事务的传播行为、隔离级别、超时设置等。

2.编程式事务管理

使用TransactionTemplate或直接使用PlatformTransactionManager,可以在代码中精确控制事务的边界。

TransactionTemplate

java 复制代码
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.support.TransactionTemplate;

public class UserService {

    @Autowired
    private TransactionTemplate transactionTemplate;

    public User createUser(final User user) {
        return transactionTemplate.execute(status -> {
            // 这里的操作会在一个事务中执行
            return userRepository.save(user);
        });
    }
}

PlatformTransactionManager

对于需要完全控制事务行为的场景,Spring还允许直接使用PlatformTransactionManager。

java 复制代码
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.support.DefaultTransactionDefinition;

public class UserServiceImpl implements UserService {

    @Autowired
    private PlatformTransactionManager transactionManager;

    public void updateUser(User user) {
        TransactionStatus status = transactionManager.getTransaction(new DefaultTransactionDefinition());
        try {
            // 这里的操作会在一个事务中执行
            userRepository.update(user);
            transactionManager.commit(status);
        } catch (Exception e) {
            transactionManager.rollback(status);
            throw e;
        }
    }
}

二、@Transactional注解深入

1.基本使用

@Transactional注解可以应用于类或方法级别。当应用于类级别时,该类中的所有公共方法都会被应用事务管理。当应用于方法级别时,只有标注了该注解的方法才会进行事务管理。

基本属性

  • readOnly: 指定事务是否为只读事务。只读事务可以帮助数据库引擎优化事务。
  • propagation: 指定事务的传播行为。
  • isolation: 指定事务的隔离级别。
  • timeout: 定义事务的超时限制(以秒为单位)。
  • rollbackFor: 指定哪些异常可以触发事务回滚。
  • noRollbackFor: 指定哪些异常不应触发事务回滚。

2.传播行为

事务的传播行为定义了事务边界的创建方式。Spring定义了多种传播行为:

  • REQUIRED: 如果当前存在事务,则加入该事务;如果当前没有事务,则创建一个新的事务。
  • SUPPORTS: 如果当前存在事务,则加入该事务;如果当前没有事务,则以非事务方式执行。
  • MANDATORY: 如果当前存在事务,则加入该事务;如果当前没有事务,则抛出异常。
  • REQUIRES_NEW: 总是创建一个新的事务,如果当前存在事务,则挂起当前事务。
  • NOT_SUPPORTED: 总是以非事务方式执行,如果当前存在事务,则挂起当前事务。
  • NEVER: 总是以非事务方式执行,如果当前存在事务,则抛出异常。
  • NESTED : 如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则表现同REQUIRED

3.隔离级别

隔离级别定义了一个事务可能受其他并发事务影响的程度。Spring支持以下隔离级别:

  • DEFAULT: 使用底层数据源的默认隔离级别。
  • READ_UNCOMMITTED: 允许读取未提交的更改。
  • READ_COMMITTED: 仅允许读取已提交的更改。
  • REPEATABLE_READ: 确保在事务内重复读取同一记录的结果一致。
  • SERIALIZABLE: 完全隔离,确保事务串行化执行。

4.事务超时设置

通过@Transactional注解的timeout属性,可以为事务指定超时时间。如果事务执行时间超过了指定的时间限制,Spring将自动回滚事务。

5.回滚规则

通过@Transactional注解的rollbackFornoRollbackFor属性,可以精确控制异常回滚行为:

  • rollbackFor: 指定哪些异常应该触发事务回滚。
  • noRollbackFor: 指定哪些异常不应该触发事务回滚。

三、事务管理的最佳实践

1.事务边界的确定

事务边界定义了事务的开始和结束,合理的事务边界可以确保事务既不过大也不过小。

  • 定义清晰的业务逻辑单元:每个事务应该对应一个清晰定义的业务逻辑单元。不应该让一个事务覆盖多个不相关的操作。
  • 避免长事务:长事务会占用数据库资源,增加锁定的范围和时间,从而影响并发性能。尽量避免不必要的长事务,及时提交或回滚。
  • 事务中的操作数量:虽然理论上事务可以包含任意数量的操作,但是在实践中,应该避免在单一事务中包含过多的操作。如果业务逻辑允许,可以将一个大事务分解为几个小事务,以提高并发性和系统稳定性。

2.只读事务的使用

只读事务是指不包含任何修改(插入、更新、删除)操作的事务。只读事务的使用有以下好处:

  • 性能优化:数据库可以对只读事务进行优化,如减少锁的使用,提升查询性能。
  • 减少副作用:标记为只读的事务明确告诉数据库和应用程序这个事务不会修改数据,有助于避免由于错误的数据修改导致的问题。

何时使用只读事务:

  • 数据查询操作:当事务仅包含数据查询操作,不涉及任何数据修改时,应将事务标记为只读。
  • 报表生成:生成报表或执行大量查询以分析数据时,使用只读事务可以提高效率。

3.避免编程式事务

尽管Spring提供了编程式事务管理的能力,但在大多数情况下,推荐使用声明式事务管理(@Transactional注解)原因如下:

  • 简化开发:声明式事务管理通过注解的方式,减少了编程的复杂度,使得事务管理更加直观和易于理解。
  • 减少代码侵入性:使用声明式事务管理,事务代码与业务代码分离,降低了代码的耦合度,提高了代码的可读性和可维护性。
  • 统一事务管理:声明式事务管理提供了一种统一的事务管理机制,使得事务管理更加标准化,易于跟踪和维护。
相关推荐
CoderIsArt33 分钟前
Redis的三种模式:主从模式,哨兵与集群模式
数据库·redis·缓存
XiaoLeisj1 小时前
【JavaEE初阶 — 多线程】单例模式 & 指令重排序问题
java·开发语言·java-ee
paopaokaka_luck2 小时前
【360】基于springboot的志愿服务管理系统
java·spring boot·后端·spring·毕业设计
dayouziei2 小时前
java的类加载机制的学习
java·学习
师太,答应老衲吧3 小时前
SQL实战训练之,力扣:2020. 无流量的帐户数(递归)
数据库·sql·leetcode
Yaml43 小时前
Spring Boot 与 Vue 共筑二手书籍交易卓越平台
java·spring boot·后端·mysql·spring·vue·二手书籍
小小小妮子~3 小时前
Spring Boot详解:从入门到精通
java·spring boot·后端
hong1616884 小时前
Spring Boot中实现多数据源连接和切换的方案
java·spring boot·后端
Channing Lewis4 小时前
salesforce case可以新建一个roll up 字段,统计出这个case下的email数量吗
数据库·salesforce
aloha_7894 小时前
从零记录搭建一个干净的mybatis环境
java·笔记·spring·spring cloud·maven·mybatis·springboot