SpringBoot事务处理

本文详细介绍了Spring Boot中如何在Service层实现事务,包括@Transactional注解的使用场景、属性及注意事项,涵盖了事务传播行为、隔离级别和回滚规则。重点讲解了@Transactional在不同情况下的失效原因和解决策略。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

介绍

        在实际的业务场景中,不光数据库要实现事务,我们的Service层业务也要实现事务。例如:要实现数据的删除,删除数据库中的数据并删除Redis缓存中的数据,他们在一个ServiceImpl的方法中,我们要实现这两个操作放在一个事务中,两个操作同时成功 / 失败,所有,要使用Spring事务。

SpringBoot中事务实现

ServiceImpl的方法 / ServiceImpl类 上加上@Transactional。

  • 方法:注解只对public方法有效(因为@Transactional 工作原理是基于AOP实现的),如果在 protected、private 或者默认方法上使用,没有作用,也不报错。
  • 类:该类的所有 public 方法将都具有该类型的事务属性

注意:在方法级别使用该注解可以覆盖类级别使用该注解。

// 这个类中的public方法如果抛出Exception,则该方法会回滚
@Transactional(rollbackFor = Exception.class)
public class DefaultFooService implements FooService {

  public Foo getFoo(String fooName) {
    // do something
  }

  // these settings have precedence for this method
  //方法上注解属性会覆盖类注解上的相同属性
  @Transactional(readOnly = false, propagation = Propagation.REQUIRES_NEW)
  public void updateFoo(Foo foo) {
    // do something
  }
}

@EnableTransactionManagement

SpringBoot启动类上加上不用加@EnableTransactionManagement注解,SpringBoot自动装配已经帮我们处理了,SpringBoot项目默认支持事务。

@Transactional

作用位置:接口、接口方法、类以及类方法

        Spring 建议不要在接口或者接口方法上使用该注解,因为这只有在使用基于接口的代理时它才会生效。

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

Transactional类

package org.springframework.transaction.annotation;

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

import org.springframework.core.annotation.AliasFor;
import org.springframework.transaction.TransactionDefinition;

@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface Transactional {

	@AliasFor("transactionManager")
	String value() default "";

	@AliasFor("value")
	String transactionManager() default "";

	Propagation propagation() default Propagation.REQUIRED;

	Isolation isolation() default Isolation.DEFAULT;

	int timeout() default TransactionDefinition.TIMEOUT_DEFAULT;

	boolean readOnly() default false;

	Class<? extends Throwable>[] rollbackFor() default {};

	String[] rollbackForClassName() default {};

	Class<? extends Throwable>[] noRollbackFor() default {};

	String[] noRollbackForClassName() default {};
}

注解的属性

属性类型描述
valueString可选的限定描述符,指定使用的事务管理器
propagationenum: Propagation可选的事务传播行为设置
isolationenum: Isolation可选的事务隔离级别设置
readOnlyboolean读写或只读事务,默认读写
timeoutint (in seconds granularity)事务超时时间设置
rollbackForClass对象数组,必须继承自Throwable导致事务回滚的异常类数组
rollbackForClassName类名数组,必须继承自Throwable导致事务回滚的异常类名字数组
noRollbackForClass对象数组,必须继承自Throwable不会导致事务回滚的异常类数组
noRollbackForClassName类名数组,必须继承自Throwable不会导致事务回滚的异常类名字数组

在Spring中定义了五种隔离级别常量

一般用默认就可以。

package org.springframework.transaction.annotation;

import org.springframework.transaction.TransactionDefinition;

public enum Isolation {

	DEFAULT(TransactionDefinition.ISOLATION_DEFAULT),

	READ_UNCOMMITTED(TransactionDefinition.ISOLATION_READ_UNCOMMITTED),

	READ_COMMITTED(TransactionDefinition.ISOLATION_READ_COMMITTED),

	REPEATABLE_READ(TransactionDefinition.ISOLATION_REPEATABLE_READ),
	
	SERIALIZABLE(TransactionDefinition.ISOLATION_SERIALIZABLE);


	private final int value;

	Isolation(int value) {
		this.value = value;
	}

	public int value() {
		return this.value;
	}
}
常量说明
TransactionDefinition.ISOLATION_DEFAULT数据库默认的隔离级别,MySQL默认采用的 REPEATABLE_READ隔离级别
TransactionDefinition.ISOLATION_READ_UNCOMMITTED最低的隔离级别,允许读取未提交的数据变更,可能会导致脏读、幻读或不可重复读
TransactionDefinition.ISOLATION_READ_COMMITTED允许读取并发事务已经提交的数据,可以阻止脏读,但是幻读或不可重复读仍有可能发生
TransactionDefinition.ISOLATION_REPEATABLE_READ对同一字段的多次读取结果都是一致的,除非数据是被本身事务自己所修改,可以阻止脏读和不可重复读,但幻读仍有可能发生。MySQL中通过MVCC解决了该隔离级别下出现幻读的可能。
TransactionDefinition.ISOLATION_SERIALIZABLE串行化隔离级别,该级别可以防止脏读、不可重复读以及幻读,但是串行化会影响性能。

Spring定义了七种事务传播行为

类型说明
PROPAGATION_REQUIRED如果当前没有事务,就新建一个事务,如果已经存在一个事务中,加入到这个事务中。这是最常见的选择
PROPAGATION_SUPPORTS支持当前事务,如果当前没有事务,就以非事务方式执行。
PROPAGATION_MANDATORY使用当前的事务,如果当前没有事务,就抛出异常。
PROPAGATION_REQUIRES_NEW新建事务,如果当前存在事务,把当前事务挂起。
PROPAGATION_NOT_SUPPORTED以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。
PROPAGATION_NEVER以非事务方式执行,如果当前存在事务,则抛出异常。
PROPAGATION_NESTED如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则执行与PROPAGATION_REQUIRED类似的操作。

Spring事务什么情况下会失效

【1】@Transactional 应用在非 public 修饰的方法上

@Transactional 工作原理是基于AOP实现的,所以,注解必须作用在public的方法上,否则失效。

【2】数据库引擎是否支持事务(MySql的MyIsam引擎不支持事物)

【3】@Transactional注解属性 propagation 设置错误

  • TransactionDefinition.PROPAGATION_SUPPORTS:如果当前存在事务,则加入该事务;如果当前没有事务,则以非事务的方式继续运行。
  • TransactionDefinition.PROPAGATION_NOT_SUPPORTED:以非事务方式运行,如果当前存在事务,则把当前事务挂起。
  • TransactionDefinition.PROPAGATION_NEVER:以非事务方式运行,如果当前存在事务,则抛出异。

【4】@Transactional 注解属性 rollbackFor 设置错误
​        Spring默认是回滚RuntimeException才回滚。当然自定义的RuntimeException异常类也是可以的。如果希望Spring能够回滚别类型的异常,那就需要使用rollbackFor去指定(当然如果是指定异常的子类,也同样会回滚)。

【5】同一个类中方法调用,导致@Transactional失效
​        在同一个类中,没有加事务的方法A调用加事务的方法B,方法B的事务失效。( 其实这还是由于使用Spring AOP代理造成的),所以:建议把整个类加上事务注解。

【6】异常被捕获了
​        这个就比较简单了,就是你自己捕捉到了异常,并且自己处理,并不会抛出到上层的方法调用。那就不会生效了。

@Transactional
public void contextLoads() {
    try {
        int i = 0;
    }catch (Exception e){
        System.out.println("不可以回滚");
    }
}

可以手动设置回滚

@Transactional
public void contextLoads() {
    try {
        int i = 0;
    }catch (Exception e){
        // 手动回滚
        TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
        System.out.println("可以回滚");
    }
}

【7】新开启一个线程
        Spring实现事务的原理是通过ThreadLocal把数据库连接绑定到当前线程中,新开启一个线程获取到的连接就不是同一个了。

<think>嗯,用户想了解SpringBoot中处理事务的方法和最佳实践,特别是关于注解、配置和示例。首先,我需要回忆一下SpringBoot事务管理的基础知识。记得事务管理主要分为声明式和编程式两种,而SpringBoot推荐使用声明式,也就是用@Transactional注解。 用户提到注解,所以我需要详细说明@Transactional的用法,包括它的参数和如何应用在方法或类上。然后配置部分,可能涉及如何启用事务管理,自动配置的原理,以及如何自定义事务管理器。比如,SpringBoot自动配置了DataSourceTransactionManager,所以用户可能不需要做太多配置,但如果需要多个数据源,可能需要手动配置。 示例代码是必须的,用户可能需要看到如何在Service层使用@Transactional,包括成功和回滚的情况。比如,一个保存用户的方法,如果发生异常,事务应该回滚。这里要注意异常类型,默认情况下只有运行时异常和错误才会回滚,所以可能需要配置rollbackFor。 最佳实践部分,应该包括如何选择合适的异常、避免自调用问题、事务的传播机制和隔离级别设置,还有性能方面的考虑,比如事务不要太长。此外,可能还需要提到测试事务的方法,比如使用@Transactional在测试中自动回滚。 还要参考用户提供的引用内容,特别是引用3和4,里面提到了@Transactional的使用和两种事务管理方式。需要确保回答覆盖这些点,并且结构清晰,分步骤说明。比如先讲注解使用,再讲配置,然后示例,最后最佳实践。 可能用户没有说出来的深层需求是,他们可能在开发中遇到了事务不生效的问题,或者想知道如何优化事务管理。所以需要强调常见的陷阱,比如自调用导致注解失效,或者异常处理不当导致不回滚。此外,最佳实践中提到的传播行为可能对复杂业务逻辑有帮助。 最后,生成相关问题的时候,要考虑用户可能接下来会问的问题,比如事务失效的原因、多数据源事务处理、隔离级别的选择等。这些问题可以帮助用户进一步深入理解事务管理。</think>### Spring Boot事务管理详解 #### 一、核心注解与配置 1. **@Transactional注解** - 声明式事务管理的核心注解,可作用于类或方法 - 主要参数说明: ```java @Transactional( propagation = Propagation.REQUIRED, // 事务传播行为 isolation = Isolation.DEFAULT, // 事务隔离级别 rollbackFor = Exception.class, // 指定回滚的异常类型 timeout = 30 // 事务超时时间(秒) ) ``` - 默认对RuntimeException和Error回滚[^3][^4] 2. **自动配置原理** - 通过`spring-boot-autoconfigure`自动配置DataSourceTransactionManager[^2] - 需确保存在有效DataSource配置: ```yaml spring: datasource: url: jdbc:mysql://localhost:3306/mydb username: root password: 123456 ``` #### 二、代码实现示例 ```java @Service public class UserService { @Autowired private UserRepository userRepository; @Transactional public void createUser(User user) { userRepository.save(user); // 触发异常测试回滚 if(user.getAge() < 0) { throw new IllegalArgumentException("年龄不合法"); } } @Transactional(propagation = Propagation.REQUIRES_NEW) public void auditUser(Long userId) { // 需要独立事务的操作 } } ``` #### 三、最佳实践指南 1. **事务粒度控制** - 保持事务方法简短,避免长期持有数据库连接 - 推荐将@Transactional注解应用于Service层而非Controller层 2. **异常处理规范** - 明确指定rollbackFor: ```java @Transactional(rollbackFor = {SQLException.class, DataAccessException.class}) ``` - 避免在事务方法内捕获异常后不抛出 3. **传播行为选择** - REQUIRED(默认):加入当前事务,没有则新建 - REQUIRES_NEW:始终新建独立事务 - NESTED:嵌套事务(需数据库支持) 4. **性能优化** - 只读事务标记: ```java @Transactional(readOnly = true) ``` - 合理设置事务超时时间 #### 四、调试与验证 1. 查看事务日志: ```properties logging.level.org.springframework.jdbc=DEBUG logging.level.org.springframework.transaction=TRACE ``` 2. 单元测试验证: ```java @SpringBootTest @Transactional // 测试后自动回滚 class UserServiceTest { @Test void testCreateUserRollback() { assertThrows(DataIntegrityViolationException.class, () -> { userService.createUser(new User("", -1)); }); } } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

龙域、白泽

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值