一、事务概念
事务是一组由一个或多个操作组成的不可分割的工作单元,这些操作要么全部成功,要么全部失败。在关系型数据库中,事务是指一组SQL语句组成的操作序列,具有四个特性:原子性、一致性、隔离性和持久性。
二、Spring 事务处理
Spring 通过TransactionManager来统一管理事务,支持声明式事务和编程式事务两种方式。其中,声明式事务可以通过AOP实现,而编程式事务可以通过编写代码来实现。
三、Spring 事务传播行为
Spring 定义了七种事务传播行为,用于配置事务的传播属性,确保多个事务之间的正确性和一致性。
1、PROPAGATION_REQUIRED(默认值)
如果当前存在事务,则加入该事务;如果不存在事务,则创建一个新事务。
@Transactional(propagation = Propagation.REQUIRED) public void method(){ // 事务代码 }
2、PROPAGATION_SUPPORTS
如果当前存在事务,则加入该事务;如果不存在事务,则以非事务的方式继续执行。
@Transactional(propagation = Propagation.SUPPORTS) public void method(){ // 事务代码 }
3、PROPAGATION_MANDATORY
如果当前存在事务,则加入该事务;如果不存在事务,则抛出异常。
@Transactional(propagation = Propagation.MANDATORY) public void method(){ // 事务代码 }
4、PROPAGATION_REQUIRES_NEW
创建一个新事务,并且暂停当前事务(如果存在)。
@Transactional(propagation = Propagation.REQUIRES_NEW) public void method(){ // 事务代码 }
5、PROPAGATION_NOT_SUPPORTED
以非事务方式执行操作,如果当前存在事务,则挂起该事务。
@Transactional(propagation = Propagation.NOT_SUPPORTED) public void method(){ // 事务代码 }
6、PROPAGATION_NEVER
以非事务方式执行操作,如果当前存在事务,则抛出异常。
@Transactional(propagation = Propagation.NEVER) public void method(){ // 事务代码 }
7、PROPAGATION_NESTED
如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则相当于PROPAGATION_REQUIRED。
@Transactional(propagation = Propagation.NESTED) public void method(){ // 事务代码 }
四、Spring 事务传播案例
下面我们通过一个简单的案例来说明 Spring 事务传播的使用。
1、创建数据库表
创建一个名为 user 的表,用于演示 Spring 事务传播功能的使用。
CREATE TABLE `user` ( `id` int(11) NOT NULL AUTO_INCREMENT, `name` varchar(255) DEFAULT NULL, `age` int(11) DEFAULT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
2、添加依赖
Pom.xml 文件中添加 Spring Boot 相关依赖。
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-jdbc</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency>
3、配置数据源
在 application.properties 文件中添加数据源相关配置。
spring.datasource.url=jdbc:mysql://localhost:3306/test?useSSL=false spring.datasource.username=root spring.datasource.password=root spring.datasource.driver-class-name=com.mysql.jdbc.Driver
4、创建User实体类
创建 User 实体类。
public class User { private int id; private String name; private int age; // 省略 getter 和 setter 方法 }
5、添加数据访问对象
创建 UserDAO 接口和实现类,用于操作数据库。
public interface UserDAO { void addUser(User user); void addUserWithRequired(User user); void addUserWithRequiresNew(User user); } @Repository public class UserDAOImpl implements UserDAO { @Autowired private JdbcTemplate jdbcTemplate; @Override public void addUser(User user) { String sql = "INSERT INTO user(name, age) VALUES(?, ?)"; jdbcTemplate.update(sql, new Object[]{user.getName(), user.getAge()}); } @Override @Transactional(propagation = Propagation.REQUIRED) public void addUserWithRequired(User user) { String sql = "INSERT INTO user(name, age) VALUES(?, ?)"; jdbcTemplate.update(sql, new Object[]{user.getName(), user.getAge()}); throw new RuntimeException(); } @Override @Transactional(propagation = Propagation.REQUIRES_NEW) public void addUserWithRequiresNew(User user) { String sql = "INSERT INTO user(name, age) VALUES(?, ?)"; jdbcTemplate.update(sql, new Object[]{user.getName(), user.getAge()}); throw new RuntimeException(); } }
6、添加服务层
创建 UserService 接口和实现类,用于操作数据库。
public interface UserService { void addUser(User user); void addUserWithRequired(User user); void addUserWithRequiresNew(User user); } @Service public class UserServiceImpl implements UserService { @Autowired private UserDAO userDAO; @Override @Transactional public void addUser(User user) { userDAO.addUser(user); throw new RuntimeException(); } @Override @Transactional public void addUserWithRequired(User user) { userDAO.addUserWithRequired(user); } @Override @Transactional public void addUserWithRequiresNew(User user) { userDAO.addUserWithRequiresNew(user); } }
7、写测试类
创建一个测试类,测试 Spring 事务传播的效果。
@RunWith(SpringJUnit4ClassRunner.class) @SpringBootTest(classes = Application.class) public class UserServiceImplTest { @Autowired private UserService userService; @Autowired private UserDAO userDAO; @Test(expected = RuntimeException.class) public void testTransactionRequired() { User user = new User(); user.setName("John"); user.setAge(20); userService.addUserWithRequired(user); } @Test(expected = RuntimeException.class) public void testTransactionRequiresNew() { User user = new User(); user.setName("John"); user.setAge(20); userService.addUserWithRequiresNew(user); } }
总结
本文详细介绍了 Spring 事务传播的概念、配置方式和七种传播行为,并提供了一个简单的案例,演示了 Spring 事务传播机制的实际使用。掌握了事务传播的知识,能够在必要的时候进行正确的配置,确保多个事务之间的正确性和一致性。