微信登录

事务管理 - 数据事务 - 管理数据操作事务

Java - Web - Spring 《事务管理 - 数据事务 - 管理数据操作事务》

一、引言

在 Java Web 开发中,Spring 框架为我们提供了强大的事务管理功能。事务是一组不可分割的操作序列,要么全部成功执行,要么全部失败回滚。在数据库操作中,事务管理尤为重要,它可以保证数据的一致性和完整性。本文将详细介绍 Spring 中的事务管理,包括声明式事务和编程式事务,并通过示例代码进行演示。

二、事务的基本概念

2.1 事务的特性(ACID)

  • 原子性(Atomicity):事务是一个不可分割的工作单位,事务中的操作要么全部成功,要么全部失败。
  • 一致性(Consistency):事务执行前后,数据库的状态必须保持一致。
  • 隔离性(Isolation):多个事务并发执行时,一个事务的执行不应该影响其他事务的执行。
  • 持久性(Durability):事务一旦提交,它对数据库的改变就是永久性的。

2.2 事务的隔离级别

Spring 支持多种事务隔离级别,常见的有:
| 隔离级别 | 描述 |
| —— | —— |
| ISOLATION_DEFAULT | 使用数据库默认的隔离级别。 |
| ISOLATION_READ_UNCOMMITTED | 允许读取未提交的数据,可能会出现脏读、不可重复读和幻读。 |
| ISOLATION_READ_COMMITTED | 只允许读取已提交的数据,避免了脏读,但可能会出现不可重复读和幻读。 |
| ISOLATION_REPEATABLE_READ | 确保在同一个事务中多次读取同一数据的结果是一致的,避免了脏读和不可重复读,但可能会出现幻读。 |
| ISOLATION_SERIALIZABLE | 最高的隔离级别,完全串行化执行事务,避免了脏读、不可重复读和幻读,但性能较低。 |

2.3 事务的传播行为

Spring 定义了 7 种事务传播行为,常见的有:
| 传播行为 | 描述 |
| —— | —— |
| PROPAGATION_REQUIRED | 如果当前存在事务,则加入该事务;如果不存在事务,则创建一个新的事务。 |
| PROPAGATION_SUPPORTS | 如果当前存在事务,则加入该事务;如果不存在事务,则以非事务方式执行。 |
| PROPAGATION_MANDATORY | 如果当前存在事务,则加入该事务;如果不存在事务,则抛出异常。 |
| PROPAGATION_REQUIRES_NEW | 无论当前是否存在事务,都创建一个新的事务,并挂起当前事务。 |

三、Spring 中的事务管理方式

3.1 编程式事务管理

编程式事务管理需要在代码中显式地管理事务的开启、提交和回滚。以下是一个简单的示例:

  1. import org.springframework.jdbc.core.JdbcTemplate;
  2. import org.springframework.transaction.PlatformTransactionManager;
  3. import org.springframework.transaction.TransactionDefinition;
  4. import org.springframework.transaction.TransactionStatus;
  5. import org.springframework.transaction.support.DefaultTransactionDefinition;
  6. public class ProgrammaticTransactionExample {
  7. private JdbcTemplate jdbcTemplate;
  8. private PlatformTransactionManager transactionManager;
  9. public ProgrammaticTransactionExample(JdbcTemplate jdbcTemplate, PlatformTransactionManager transactionManager) {
  10. this.jdbcTemplate = jdbcTemplate;
  11. this.transactionManager = transactionManager;
  12. }
  13. public void transferMoney(int fromAccount, int toAccount, double amount) {
  14. TransactionDefinition def = new DefaultTransactionDefinition();
  15. TransactionStatus status = transactionManager.getTransaction(def);
  16. try {
  17. // 从源账户扣除金额
  18. jdbcTemplate.update("UPDATE accounts SET balance = balance -? WHERE id =?", amount, fromAccount);
  19. // 模拟异常
  20. if (true) {
  21. throw new RuntimeException("Simulated exception");
  22. }
  23. // 向目标账户添加金额
  24. jdbcTemplate.update("UPDATE accounts SET balance = balance +? WHERE id =?", amount, toAccount);
  25. transactionManager.commit(status);
  26. } catch (Exception e) {
  27. transactionManager.rollback(status);
  28. throw e;
  29. }
  30. }
  31. }

3.2 声明式事务管理

声明式事务管理通过 AOP(面向切面编程)实现,只需要在配置文件或使用注解进行简单配置,就可以将事务管理逻辑与业务逻辑分离。以下是使用注解的示例:

  1. import org.springframework.beans.factory.annotation.Autowired;
  2. import org.springframework.jdbc.core.JdbcTemplate;
  3. import org.springframework.stereotype.Service;
  4. import org.springframework.transaction.annotation.Transactional;
  5. @Service
  6. public class DeclarativeTransactionExample {
  7. private JdbcTemplate jdbcTemplate;
  8. @Autowired
  9. public DeclarativeTransactionExample(JdbcTemplate jdbcTemplate) {
  10. this.jdbcTemplate = jdbcTemplate;
  11. }
  12. @Transactional
  13. public void transferMoney(int fromAccount, int toAccount, double amount) {
  14. // 从源账户扣除金额
  15. jdbcTemplate.update("UPDATE accounts SET balance = balance -? WHERE id =?", amount, fromAccount);
  16. // 模拟异常
  17. if (true) {
  18. throw new RuntimeException("Simulated exception");
  19. }
  20. // 向目标账户添加金额
  21. jdbcTemplate.update("UPDATE accounts SET balance = balance +? WHERE id =?", amount, toAccount);
  22. }
  23. }

在 Spring 配置文件中,需要开启事务注解支持:

  1. <tx:annotation-driven transaction-manager="transactionManager"/>

四、示例代码配置与运行

4.1 配置 Spring 项目

首先,需要在 pom.xml 中添加相关依赖:

  1. <dependencies>
  2. <dependency>
  3. <groupId>org.springframework</groupId>
  4. <artifactId>spring-context</artifactId>
  5. <version>5.3.18</version>
  6. </dependency>
  7. <dependency>
  8. <groupId>org.springframework</groupId>
  9. <artifactId>spring-jdbc</artifactId>
  10. <version>5.3.18</version>
  11. </dependency>
  12. <dependency>
  13. <groupId>mysql</groupId>
  14. <artifactId>mysql-connector-java</artifactId>
  15. <version>8.0.26</version>
  16. </dependency>
  17. </dependencies>

4.2 配置数据源和事务管理器

  1. <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
  2. <property name="driverClassName" value="com.mysql.cj.jdbc.Driver"/>
  3. <property name="url" value="jdbc:mysql://localhost:3306/test"/>
  4. <property name="username" value="root"/>
  5. <property name="password" value="password"/>
  6. </bean>
  7. <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
  8. <property name="dataSource" ref="dataSource"/>
  9. </bean>
  10. <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
  11. <property name="dataSource" ref="dataSource"/>
  12. </bean>
  13. <tx:annotation-driven transaction-manager="transactionManager"/>

4.3 测试代码

  1. import org.springframework.context.ApplicationContext;
  2. import org.springframework.context.support.ClassPathXmlApplicationContext;
  3. public class Main {
  4. public static void main(String[] args) {
  5. ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
  6. DeclarativeTransactionExample example = context.getBean(DeclarativeTransactionExample.class);
  7. try {
  8. example.transferMoney(1, 2, 100.0);
  9. } catch (Exception e) {
  10. System.out.println("Transaction rolled back: " + e.getMessage());
  11. }
  12. }
  13. }

五、总结

Spring 提供了强大的事务管理功能,编程式事务管理适合处理复杂的事务逻辑,而声明式事务管理则更简洁,将事务管理逻辑与业务逻辑分离,提高了代码的可维护性。在实际开发中,应根据具体需求选择合适的事务管理方式。同时,要合理设置事务的隔离级别和传播行为,以保证数据的一致性和完整性。通过本文的介绍和示例代码,相信你已经对 Spring 中的事务管理有了更深入的理解。

事务管理 - 数据事务 - 管理数据操作事务