Spring Boot 事务管理:声明式与编程式深度解析
各位看官,大家好!今天咱们聊聊Spring Boot里一个至关重要,却又容易让人摸不着头脑的家伙——事务管理。别怕,这玩意儿虽然听起来玄乎,但只要咱们抽丝剥茧,保证让它变得像隔壁老王家的烤串一样,香气扑鼻,容易上手!
想象一下,你正在开发一个银行转账系统。A账户要给B账户转100块钱。这个过程至少包含两个步骤:A账户扣钱,B账户加钱。如果在A账户扣钱成功后,B账户加钱失败了(比如网络崩了),那可就麻烦了!A账户的钱凭空消失,B账户也没收到钱,这简直是人间惨剧!
这就是事务要解决的问题。事务,简单来说,就是把一系列操作捆绑成一个原子操作。要么全部成功,要么全部失败,保证数据的一致性。
Spring Boot为我们提供了两种事务管理的方式:声明式事务和编程式事务。咱们先从声明式事务开始,因为它就像一个贴心的管家,帮你打理一切,省心省力。
声明式事务:优雅的管家
声明式事务,顾名思义,就是通过声明的方式来定义事务。我们只需要在方法或者类上添加注解,告诉Spring:“嘿,这个方法/类里面的操作需要在一个事务里执行!”Spring就会自动帮我们处理事务的开始、提交、回滚等操作。
1. 引入依赖
首先,确保你的项目中包含了Spring Boot的事务管理依赖。通常情况下,spring-boot-starter-data-jpa
或者spring-boot-starter-jdbc
已经包含了spring-tx
,所以不需要额外引入。如果你的项目没有这些依赖,就需要手动添加:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
2. 开启事务支持
在你的Spring Boot应用主类上添加@EnableTransactionManagement
注解,开启事务管理功能。
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.transaction.annotation.EnableTransactionManagement;
@SpringBootApplication
@EnableTransactionManagement
public class TransactionApplication {
public static void main(String[] args) {
SpringApplication.run(TransactionApplication.class, args);
}
}
3. 使用@Transactional
注解
这是声明式事务的核心。@Transactional
注解可以添加到类或者方法上。
- 添加到类上: 表示该类中所有
public
方法都将在事务中执行。 - 添加到方法上: 表示只有该方法在事务中执行。
示例:银行转账
假设我们有一个AccountService
类,负责处理账户相关的业务逻辑。
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@Service
public class AccountService {
@Autowired
private AccountRepository accountRepository;
@Transactional
public void transfer(Long fromAccountId, Long toAccountId, Double amount) {
Account fromAccount = accountRepository.findById(fromAccountId).orElseThrow(() -> new RuntimeException("From account not found"));
Account toAccount = accountRepository.findById(toAccountId).orElseThrow(() -> new RuntimeException("To account not found"));
fromAccount.setBalance(fromAccount.getBalance() - amount);
toAccount.setBalance(toAccount.getBalance() + amount);
accountRepository.save(fromAccount);
accountRepository.save(toAccount);
}
}
在这个例子中,transfer
方法被@Transactional
注解标记,这意味着该方法中的所有操作(包括查询账户、扣款、加款、保存账户)都将在一个事务中执行。如果其中任何一个操作失败,整个事务将会回滚,保证数据的一致性。
@Transactional
注解的属性
@Transactional
注解有很多属性,可以用来控制事务的行为。下面列出一些常用的属性:
属性名 | 描述 | 默认值 |
---|---|---|
propagation |
事务传播行为。定义了当一个方法被调用时,如何处理已存在的事务。 | Propagation.REQUIRED |
isolation |
事务隔离级别。定义了多个事务并发执行时,一个事务对数据的修改,对其他事务的可见性。 | Isolation.DEFAULT |
timeout |
事务超时时间。如果事务在指定时间内没有完成,则会自动回滚。单位为秒。 | 默认值由数据库决定 |
readOnly |
是否为只读事务。如果是只读事务,则可以进行一些优化,例如禁用脏读检查。 | false |
rollbackFor |
指定哪些异常需要回滚事务。默认情况下,只有RuntimeException 及其子类和Error 才会导致事务回滚。 |
默认回滚所有RuntimeException 和Error |
noRollbackFor |
指定哪些异常不需要回滚事务。 | 无 |
transactionManager |
指定使用的事务管理器。如果你的应用中配置了多个事务管理器,你需要指定使用哪个事务管理器。 | 默认值由Spring决定 |
事务传播行为(propagation
)
事务传播行为是@Transactional
注解中最复杂,但也最重要的属性之一。它定义了当一个被@Transactional
注解标记的方法被另一个被@Transactional
注解标记的方法调用时,事务应该如何处理。
Spring提供了以下几种事务传播行为:
传播行为 | 描述 |
---|