Spring 事务管理机制介绍
1. 事务的基本概念
事务是一组不可分割的数据库操作序列,这些操作要么全部成功执行,要么全部失败回滚。事务具有四个特性,即 ACID 特性:
- 原子性(Atomicity):事务是一个不可分割的工作单位,事务中的操作要么全部成功,要么全部失败。
- 一致性(Consistency):事务执行前后,数据库的状态必须保持一致。
- 隔离性(Isolation):多个事务并发执行时,一个事务的执行不应该影响其他事务的执行。
- 持久性(Durability):事务一旦提交,其对数据库的改变是永久性的。
2. Spring 事务管理的核心接口
Spring 事务管理主要基于以下几个核心接口:
- PlatformTransactionManager:这是事务管理器的核心接口,它定义了事务的基本操作,如获取事务、提交事务和回滚事务。不同的持久化框架有不同的实现类,例如
DataSourceTransactionManager
用于 JDBC 事务管理,HibernateTransactionManager
用于 Hibernate 事务管理。 - TransactionDefinition:该接口定义了事务的属性,包括隔离级别、传播行为、超时时间和是否只读等。
- TransactionStatus:它代表了当前事务的状态,通过该接口可以进行事务的提交、回滚等操作。
3. Spring 事务管理的实现方式
Spring 提供了两种事务管理的实现方式:
- 编程式事务管理:通过编写代码来管理事务,需要手动获取事务、提交事务或回滚事务。这种方式比较灵活,但代码冗余度高,不适合大规模使用。
- 声明式事务管理:通过配置的方式来管理事务,无需在业务代码中显式地编写事务管理代码。声明式事务管理又分为基于 XML 配置和基于注解两种方式,其中基于注解的方式更为常用,使用
@Transactional
注解可以方便地为方法或类添加事务支持。
Spring 事务的嵌套实现
1. 事务传播行为
事务的嵌套涉及到事务的传播行为,TransactionDefinition
接口定义了 7 种事务传播行为,常用的有以下几种:
- PROPAGATION_REQUIRED:如果当前存在事务,则加入该事务;如果当前没有事务,则创建一个新的事务。这是默认的传播行为。
- PROPAGATION_REQUIRES_NEW:无论当前是否存在事务,都会创建一个新的事务,并挂起当前事务(如果存在)。
- PROPAGATION_NESTED:如果当前存在事务,则在嵌套事务中执行;如果当前没有事务,则创建一个新的事务。嵌套事务是外部事务的一部分,外部事务回滚时,嵌套事务也会回滚,但嵌套事务回滚不会影响外部事务。
2. 示例代码
下面是一个使用 Spring Boot 和 JPA 实现事务嵌套的示例:
首先,确保在 pom.xml
中添加必要的依赖:
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<scope>runtime</scope>
</dependency>
</dependencies>
定义实体类 User
:
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
@Entity
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
public User() {
}
public User(String name) {
this.name = name;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
定义 UserRepository
接口:
import org.springframework.data.jpa.repository.JpaRepository;
public interface UserRepository extends JpaRepository<User, Long> {
}
定义服务类 UserService
,其中包含嵌套事务的方法:
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
@Service
public class UserService {
@Autowired
private UserRepository userRepository;
@Transactional(propagation = Propagation.REQUIRED)
public void outerTransaction() {
User user1 = new User("User1");
userRepository.save(user1);
try {
innerTransaction();
} catch (Exception e) {
System.out.println("Inner transaction failed, but outer transaction may continue.");
}
User user2 = new User("User2");
userRepository.save(user2);
}
@Transactional(propagation = Propagation.NESTED)
public void innerTransaction() {
User user3 = new User("User3");
userRepository.save(user3);
throw new RuntimeException("Inner transaction exception");
}
}
在控制器中调用服务方法:
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class UserController {
@Autowired
private UserService userService;
@GetMapping("/testTransaction")
public String testTransaction() {
userService.outerTransaction();
return "Transaction test completed.";
}
}
代码解释
outerTransaction
方法使用@Transactional(propagation = Propagation.REQUIRED)
注解,表示如果当前没有事务,则创建一个新的事务。innerTransaction
方法使用@Transactional(propagation = Propagation.NESTED)
注解,表示在嵌套事务中执行。当innerTransaction
方法抛出异常时,嵌套事务会回滚,但外部事务不会受到影响,user2
仍然会被保存到数据库中。
通过以上示例,你可以看到如何在 Spring 中实现事务的嵌套。根据不同的业务需求,选择合适的事务传播行为可以确保事务的正确执行。