事务管理
1. 什么是事务?
事务(Transaction)是一组操作的集合,这些操作要么全部成功,要么全部失败,是一个不可分割的工作单元。事务的四个基本特性简称为 ACID:
- 原子性(Atomicity):事务中的所有操作要么全部完成,要么全部不完成。
- 一致性(Consistency):事务执行前后,数据库从一个一致性状态转变为另一个一致性状态。
- 隔离性(Isolation):一个事务的执行不受其他事务的干扰。
- 持久性(Durability):事务一旦提交,结果将永久保存。
2. Spring 事务管理概述
Spring 提供了对事务管理的支持,使得开发者可以方便地在业务逻辑中使用事务而无需依赖底层的数据库管理系统。Spring 的事务管理有两种主要方式:
- 编程式事务管理:通过代码显式地管理事务,灵活但复杂。
- 声明式事务管理:通过注解或 XML 配置,声明事务边界,简洁且常用。
3. 配置 Spring 事务管理
1.引入依赖: 在 pom.xml 中引入 Spring 的数据访问和事务管理依赖:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</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 Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
4. 声明式事务管理
声明式事务管理是通过注解 @Transactional 来声明某个方法或类中的所有方法都在事务中运行。
1. 示例实体类: 假设我们有一个简单的 Account 实体类:
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
@Entity
public class Account {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String owner;
private Double balance;
// 构造器、Getter 和 Setter 方法
public Account() {}
public Account(String owner, Double balance) {
this.owner = owner;
this.balance = balance;
}
// Getter 和 Setter 方法
}
2. 创建 Repository 接口: 创建一个继承 JpaRepository 的接口 AccountRepository:
import org.springframework.data.jpa.repository.JpaRepository;
public interface AccountRepository extends JpaRepository<Account, Long> {}
3. 编写服务类: 在 AccountService 中使用 @Transactional 管理事务。这里实现一个简单的转账操作,确保在同一事务中,如果任何操作失败,整个转账操作将回滚。
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 transferMoney(Long fromAccountId, Long toAccountId, Double amount) {
Account fromAccount = accountRepository.findById(fromAccountId).orElseThrow();
Account toAccount = accountRepository.findById(toAccountId).orElseThrow();
fromAccount.setBalance(fromAccount.getBalance() - amount);
toAccount.setBalance(toAccount.getBalance() + amount);
accountRepository.save(fromAccount);
accountRepository.save(toAccount);
// 模拟一个异常,确保事务回滚
if (toAccount.getBalance() > 10000) {
throw new RuntimeException("Transaction exceeds limit!");
}
}
}
4. 编写控制器类: 创建一个控制器 AccountController 来处理 HTTP 请求并调用 AccountService:
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
@RestController
@RequestMapping("/accounts")
public class AccountController {
@Autowired
private AccountService accountService;
@PostMapping("/transfer")
public String transferMoney(@RequestParam Long fromAccountId,
@RequestParam Long toAccountId,
@RequestParam Double amount) {
try {
accountService.transferMoney(fromAccountId, toAccountId, amount);
return "Transfer successful!";
} catch (Exception e) {
return "Transfer failed: " + e.getMessage();
}
}
}
5. 运行与测试: 现在,你可以运行这个 Spring Boot 应用程序,并通过 Postman 或类似工具发送 HTTP 请求来测试转账操作。
5. 编程式事务管理
编程式事务管理允许在代码中手动管理事务。使用 TransactionTemplate 或 PlatformTransactionManager 可以更细粒度地控制事务边界。
1. 示例: 使用 TransactionTemplate 实现编程式事务管理:
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.support.TransactionTemplate;
@Service
public class AccountService {
@Autowired
private AccountRepository accountRepository;
@Autowired
private TransactionTemplate transactionTemplate;
public void transferMoney(Long fromAccountId, Long toAccountId, Double amount) {
transactionTemplate.execute(status -> {
Account fromAccount = accountRepository.findById(fromAccountId).orElseThrow();
Account toAccount = accountRepository.findById(toAccountId).orElseThrow();
fromAccount.setBalance(fromAccount.getBalance() - amount);
toAccount.setBalance(toAccount.getBalance() + amount);
accountRepository.save(fromAccount);
accountRepository.save(toAccount);
// 模拟一个异常,确保事务回滚
if (toAccount.getBalance() > 10000) {
status.setRollbackOnly();
}
return null;
});
}
}
6. 事务传播行为
Spring 提供了多种事务传播行为(Propagation),用于控制一个事务方法是如何影响调用链中的其他事务。常见的传播行为包括:
- REQUIRED:如果当前存在事务,则加入该事务;如果当前没有事务,则创建一个新的事务。
- REQUIRES_NEW:总是创建一个新的事务,如果当前存在事务,则暂停当前事务。
- MANDATORY:必须在一个已存在的事务中运行,如果没有事务存在,则抛出异常。
- SUPPORTS:如果当前存在事务,则加入该事务;如果当前没有事务,则以非事务方式运行。
- NOT_SUPPORTED:总是以非事务方式运行,如果当前存在事务,则暂停当前事务。
- NEVER:必须以非事务方式运行,如果当前存在事务,则抛出异常。
- NESTED:如果当前存在事务,则在嵌套事务中执行,如果当前没有事务,则创建一个新的事务。
7. 结论
Spring 的事务管理为开发者提供了强大的工具,使得复杂的事务操作变得简单。通过声明式事务管理,开发者可以轻松地将事务逻辑与业务逻辑分离,确保数据的一致性与完整性。在一些特殊情况下,编程式事务管理也提供了灵活的控制手段。