Spring中的事务

Spring中的事务

请类比MySQL中的事务,因为数据库操作不是原子性的,所以可能存在一些问题。例如我们代码的执行过程中,需要在表A中新增一条数据,在表B中也新增一条有关的数据。如果因为线路不稳定,表A新增成功了,表B新增失败了。最终结果自然是失败。但是数据库中会多出一条脏数据。因为表A已经新增成功了。所以我们就需要使用事务这一功能将操作强制原子化。

安装和配置

Spring-JDBC是Spring框架中对JDBC的增强工具类,通过Maven引入

1
2
3
4
5
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>5.3.39</version>
</dependency>

使用类来进行配置

1
2
3
4
5
6
7
8
@Configuration
@EnableTransactionManagement
public class AppConfig {
@Bean
public PlatformTransactionManager transactionManager(DataSource dataSource) {
return new DataSourceTransactionManager(dataSource);
}
}

使用

很简单,在有关数据库操作的函数前加上@Transactional注释就能够声明为事务管理操作

1
2
3
4
5
6
7
8
9
10
11
@Service
public class OrderServiceImpl implements OrderService {
@Override
@Transactional
public void createOrder(Order order) {
// 数据库操作1
orderDao.insert(order);
// 数据库操作2
inventoryDao.deduct(order.getItemId());
}
}

参数

使用该注释的参数模板是:

1
2
3
4
5
6
@Transactional(
isolation = Isolation.READ_COMMITTED, // 隔离级别
propagation = Propagation.REQUIRED, // 传播行为
timeout = 30, // 超时秒数
rollbackFor = Exception.class // 回滚异常
)

事务隔离级别定义了多个事务并发执行时,彼此之间的可见性和影响程度。Spring支持标准SQL定义的4种隔离级别,用于解决并发事务可能引发的数据一致性问题。

1. 读未提交(READ_UNCOMMITTED)

  • 问题:允许读取其他事务未提交的修改。
  • 风险:脏读(Dirty Read)、不可重复读(Non-Repeatable Read)、幻读(Phantom Read)。
  • 适用场景:对一致性要求极低,追求高并发性能。

2. 读已提交(READ_COMMITTED)

  • 默认值:多数数据库(如Oracle)的默认隔离级别。
  • 解决:避免脏读,但允许不可重复读和幻读。
  • 适用场景:允许事务间看到已提交的数据变化(如统计报表)。

3. 可重复读(REPEATABLE_READ)

  • 默认值:MySQL的默认隔离级别。
  • 解决:避免脏读和不可重复读,但允许幻读。
  • 机制:事务内多次读取同一数据的结果一致,但新增数据可能被其他事务插入(幻读)。

4. 串行化(SERIALIZABLE)

  • 解决:强制事务串行执行,避免所有并发问题(脏读、不可重复读、幻读)。
  • 代价:性能最低,仅适用于严格要求一致性且并发量小的场景。

传播行为:

传播行为定义了事务方法在调用其他事务方法时,事务如何传播。Spring提供了7种传播行为,以下是常见类型:

1. REQUIRED(默认)

  • 规则:如果当前存在事务,则加入该事务;否则新建一个事务。
  • 场景:大多数业务方法(如订单和库存操作需在同一个事务中)。

2. REQUIRES_NEW

  • 规则:无论当前是否存在事务,都新建一个事务,并挂起当前事务(如果存在)。
  • 场景:日志记录(即使主事务回滚,日志仍需提交)。

3. NESTED

  • 规则:如果当前存在事务,则在嵌套事务(保存点)中执行;否则新建事务。
  • 特点:嵌套事务回滚不影响外层事务,但外层事务回滚会导致嵌套事务回滚。
  • 场景:复杂业务的分步操作(如订单创建成功后,部分子操作可独立回滚)。

4. SUPPORTS

  • 规则:如果当前存在事务,则加入;否则以非事务方式运行。
  • 场景:查询方法可适应有无事务的环境。

5. NOT_SUPPORTED

  • 规则:以非事务方式执行,挂起当前事务(如果存在)。
  • 场景:某些不需要事务的操作(如发送消息)。

6. MANDATORY

  • 规则:强制当前必须存在事务,否则抛出异常。
  • 场景:确保方法必须在事务上下文中调用。

7. NEVER

  • 规则:强制当前不能存在事务,否则抛出异常。
  • 场景:禁止事务的方法(如性能敏感的只读操作)。