Spring事务
Spring 事务是 Spring 框架中非常重要的特性之一,它为开发者提供了一种简单而强大的方式来管理数据库操作的一致性和完整性。以下从多个方面对 Spring 事务进行详细介绍:
1. 事务的基本概念
在数据库操作中,事务是一组不可分割的操作序列,这些操作要么全部成功执行,要么全部失败回滚。事务具有四个特性,即 ACID:
- 原子性(Atomicity):事务是一个不可分割的工作单位,事务中的操作要么全部成功,要么全部失败。
- 一致性(Consistency):事务执行前后,数据库的状态必须保持一致。
- 隔离性(Isolation):多个事务并发执行时,一个事务的执行不应该影响其他事务的执行。
- 持久性(Durability):事务一旦提交,其结果应该永久保存在数据库中。
2. Spring 事务管理的方式
Spring 提供了两种事务管理方式:编程式事务管理和声明式事务管理。
2.1 编程式事务管理
- 描述:通过编写代码来管理事务的开始、提交和回滚。这种方式比较灵活,但代码侵入性强,会增加代码的复杂度。
- 示例:
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.support.DefaultTransactionDefinition;
import javax.sql.DataSource;
public class ProgrammaticTransactionExample {
private DataSourceTransactionManager transactionManager;
public ProgrammaticTransactionExample(DataSource dataSource) {
this.transactionManager = new DataSourceTransactionManager(dataSource);
}
public void performTransaction() {
// 创建事务定义
TransactionDefinition def = new DefaultTransactionDefinition();
// 获取事务状态
TransactionStatus status = transactionManager.getTransaction(def);
try {
// 执行数据库操作
// ...
// 提交事务
transactionManager.commit(status);
} catch (Exception e) {
// 回滚事务
transactionManager.rollback(status);
}
}
}
2.2 声明式事务管理
- 描述:通过配置的方式来管理事务,而不需要在代码中显式地编写事务管理代码。这种方式减少了代码的侵入性,提高了代码的可维护性。Spring 支持基于 XML 配置和基于注解的声明式事务管理,其中基于注解的方式更为常用。
- 示例(基于注解):
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@Service
public class UserService {
@Transactional
public void transferMoney() {
// 执行数据库操作
// ...
}
}
3. 事务的传播行为
事务的传播行为定义了在一个事务方法调用另一个事务方法时,事务应该如何传播。Spring 定义了 7 种传播行为,常用的有以下几种:
- REQUIRED(默认):如果当前存在事务,则加入该事务;如果当前没有事务,则创建一个新的事务。
- REQUIRES_NEW:无论当前是否存在事务,都会创建一个新的事务,并挂起当前事务(如果存在)。
- SUPPORTS:如果当前存在事务,则加入该事务;如果当前没有事务,则以非事务方式执行。
- NOT_SUPPORTED:以非事务方式执行操作,如果当前存在事务,则挂起当前事务。
- MANDATORY:如果当前存在事务,则加入该事务;如果当前没有事务,则抛出异常。
- NEVER:以非事务方式执行操作,如果当前存在事务,则抛出异常。
- NESTED:如果当前存在事务,则在嵌套事务内执行;如果当前没有事务,则创建一个新的事务。
示例:
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
@Service
public class UserService {
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void doSomething() {
// 执行数据库操作
// ...
}
}
4. 事务的隔离级别
事务的隔离级别定义了一个事务对其他事务的可见性。Spring 支持以下几种隔离级别,与数据库的隔离级别相对应:
- DEFAULT:使用数据库默认的隔离级别。
- READ_UNCOMMITTED:最低的隔离级别,允许读取尚未提交的数据变更,可能会导致脏读、不可重复读和幻读问题。
- READ_COMMITTED:允许读取已经提交的数据,避免了脏读,但可能会出现不可重复读和幻读问题。
- REPEATABLE_READ:确保在同一个事务中多次读取同一数据的结果是一致的,避免了脏读和不可重复读,但可能会出现幻读问题。
- SERIALIZABLE:最高的隔离级别,通过强制事务串行执行,避免了脏读、不可重复读和幻读问题,但会降低并发性能。
示例:
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Transactional;
@Service
public class UserService {
@Transactional(isolation = Isolation.READ_COMMITTED)
public void doSomething() {
// 执行数据库操作
// ...
}
}
5. 事务的回滚规则
在默认情况下,Spring 事务只会在抛出 RuntimeException
及其子类时进行回滚。可以通过 @Transactional
注解的 rollbackFor
和 noRollbackFor
属性来指定需要回滚和不需要回滚的异常类型。
示例:
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@Service
public class UserService {
@Transactional(rollbackFor = Exception.class)
public void doSomething() throws Exception {
// 执行数据库操作
// ...
throw new Exception("Something went wrong");
}
}
6. 开启 Spring 事务支持
要使用 Spring 声明式事务管理,需要在配置类上添加 @EnableTransactionManagement
注解。
示例:
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.jdbc.datasource.DriverManagerDataSource;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import javax.sql.DataSource;
@Configuration
@EnableTransactionManagement
public class AppConfig {
@Bean
public DataSource dataSource() {
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setDriverClassName("com.mysql.cj.jdbc.Driver");
dataSource.setUrl("jdbc:mysql://localhost:3306/test");
dataSource.setUsername("root");
dataSource.setPassword("password");
return dataSource;
}
}
综上所述,Spring 事务管理提供了丰富的功能和灵活的配置选项,开发者可以根据具体的业务需求选择合适的事务管理方式、传播行为、隔离级别和回滚规则,确保数据库操作的一致性和完整性。