在 Java Web 开发中,Spring 框架为我们提供了强大的事务管理功能。事务是一组不可分割的操作序列,要么全部成功执行,要么全部失败回滚。在数据库操作中,事务管理尤为重要,它可以保证数据的一致性和完整性。本文将详细介绍 Spring 中的事务管理,包括声明式事务和编程式事务,并通过示例代码进行演示。
Spring 支持多种事务隔离级别,常见的有:
| 隔离级别 | 描述 |
| —— | —— |
| ISOLATION_DEFAULT
| 使用数据库默认的隔离级别。 |
| ISOLATION_READ_UNCOMMITTED
| 允许读取未提交的数据,可能会出现脏读、不可重复读和幻读。 |
| ISOLATION_READ_COMMITTED
| 只允许读取已提交的数据,避免了脏读,但可能会出现不可重复读和幻读。 |
| ISOLATION_REPEATABLE_READ
| 确保在同一个事务中多次读取同一数据的结果是一致的,避免了脏读和不可重复读,但可能会出现幻读。 |
| ISOLATION_SERIALIZABLE
| 最高的隔离级别,完全串行化执行事务,避免了脏读、不可重复读和幻读,但性能较低。 |
Spring 定义了 7 种事务传播行为,常见的有:
| 传播行为 | 描述 |
| —— | —— |
| PROPAGATION_REQUIRED
| 如果当前存在事务,则加入该事务;如果不存在事务,则创建一个新的事务。 |
| PROPAGATION_SUPPORTS
| 如果当前存在事务,则加入该事务;如果不存在事务,则以非事务方式执行。 |
| PROPAGATION_MANDATORY
| 如果当前存在事务,则加入该事务;如果不存在事务,则抛出异常。 |
| PROPAGATION_REQUIRES_NEW
| 无论当前是否存在事务,都创建一个新的事务,并挂起当前事务。 |
编程式事务管理需要在代码中显式地管理事务的开启、提交和回滚。以下是一个简单的示例:
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.support.DefaultTransactionDefinition;
public class ProgrammaticTransactionExample {
private JdbcTemplate jdbcTemplate;
private PlatformTransactionManager transactionManager;
public ProgrammaticTransactionExample(JdbcTemplate jdbcTemplate, PlatformTransactionManager transactionManager) {
this.jdbcTemplate = jdbcTemplate;
this.transactionManager = transactionManager;
}
public void transferMoney(int fromAccount, int toAccount, double amount) {
TransactionDefinition def = new DefaultTransactionDefinition();
TransactionStatus status = transactionManager.getTransaction(def);
try {
// 从源账户扣除金额
jdbcTemplate.update("UPDATE accounts SET balance = balance -? WHERE id =?", amount, fromAccount);
// 模拟异常
if (true) {
throw new RuntimeException("Simulated exception");
}
// 向目标账户添加金额
jdbcTemplate.update("UPDATE accounts SET balance = balance +? WHERE id =?", amount, toAccount);
transactionManager.commit(status);
} catch (Exception e) {
transactionManager.rollback(status);
throw e;
}
}
}
声明式事务管理通过 AOP(面向切面编程)实现,只需要在配置文件或使用注解进行简单配置,就可以将事务管理逻辑与业务逻辑分离。以下是使用注解的示例:
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@Service
public class DeclarativeTransactionExample {
private JdbcTemplate jdbcTemplate;
@Autowired
public DeclarativeTransactionExample(JdbcTemplate jdbcTemplate) {
this.jdbcTemplate = jdbcTemplate;
}
@Transactional
public void transferMoney(int fromAccount, int toAccount, double amount) {
// 从源账户扣除金额
jdbcTemplate.update("UPDATE accounts SET balance = balance -? WHERE id =?", amount, fromAccount);
// 模拟异常
if (true) {
throw new RuntimeException("Simulated exception");
}
// 向目标账户添加金额
jdbcTemplate.update("UPDATE accounts SET balance = balance +? WHERE id =?", amount, toAccount);
}
}
在 Spring 配置文件中,需要开启事务注解支持:
<tx:annotation-driven transaction-manager="transactionManager"/>
首先,需要在 pom.xml
中添加相关依赖:
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.3.18</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>5.3.18</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.26</version>
</dependency>
</dependencies>
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="com.mysql.cj.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/test"/>
<property name="username" value="root"/>
<property name="password" value="password"/>
</bean>
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="dataSource"/>
</bean>
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
<tx:annotation-driven transaction-manager="transactionManager"/>
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Main {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
DeclarativeTransactionExample example = context.getBean(DeclarativeTransactionExample.class);
try {
example.transferMoney(1, 2, 100.0);
} catch (Exception e) {
System.out.println("Transaction rolled back: " + e.getMessage());
}
}
}
Spring 提供了强大的事务管理功能,编程式事务管理适合处理复杂的事务逻辑,而声明式事务管理则更简洁,将事务管理逻辑与业务逻辑分离,提高了代码的可维护性。在实际开发中,应根据具体需求选择合适的事务管理方式。同时,要合理设置事务的隔离级别和传播行为,以保证数据的一致性和完整性。通过本文的介绍和示例代码,相信你已经对 Spring 中的事务管理有了更深入的理解。