Spring 事务管理主要通过声明式事务和编程式事务两种方式来实现。
在方法上添加 @Transactional
注解。进入方法时自动开启事务,方法执行完自动提交事务,如果发生了没有处理的异常会自动回滚事务。
@Service
@Transactional
public class YourService {
// 业务逻辑代码
}
@Transactional
作用范围
@Transactional
可以用来修饰方法或类:
参数:
参数 | 说明 |
---|---|
value | 当配置了多个事务管理器时,可以使用该属性指定选择哪个事务管理器 |
transactionManager | 同上 |
propagation | 事务的传播行为,默认值:Propagation.REQUIRED |
isolation | 事务的隔离级别,默认值:Isolation.DEFAULT |
timeout | 事务的超时时间,默认值:-1 ,如果超时但事务还没完成,则自动回滚事务 |
readOnly | 如果事务实际上是只读的,则可以将布尔标志设置为 true ,从而允许在运行时进行相应的优化。默认值:false |
rollbackFor | 定义零(0)个或多个异常类型,指示哪些异常类型必须导致事务回滚 |
rollbackForClassName | 定义零(0)个或多个异常名称模式,指示哪些异常类型必须导致事务回滚 |
noRollbackFor | 定义零(0)个或多个异常类型,指示哪些异常类型不能导致事务回滚 |
noRollbackForClassName | 定义零(0)个或多个异常名称模式,指示哪些异常类型不能导致事务回滚 |
手动回滚事务
有时候发生了异常也不会自动回滚,因为可能这个异常被处理了,没有抛出。
此时我们依然想让事务回滚,可以采取手动的方式:
TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
事务隔离级别
如果设置为 Isolation.DEFAULT
,就以数据库的为准。如果设置了其他的,比如 Isolation.READ_COMMITTED
读已提交,就按 Spring 设置的为准。
事务传播机制是指在一个包含多个事务操作的方法或代码块中,各个事务之间相互影响和传播的规则。
以下是 7 种事务传播行为:
例:
package org.example.springboottransaction.service;
import org.example.springboottransaction.mapper.UserMapper;
import org.example.springboottransaction.model.UserInfo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@Service
public class TransactionService {
@Autowired
UserMapper userMapper;
@Transactional
public void transactionMethod1() {
// 一些业务逻辑...
UserInfo userInfo = new UserInfo();
userInfo.setUsername("ZhangSan");
userInfo.setPassword("123");
userMapper.add(userInfo);
System.out.println("Method 1 executed");
}
@Transactional
public void transactionMethod2() {
// 另一些业务逻辑...
UserInfo userInfo = new UserInfo();
userInfo.setUsername("LiSi");
userInfo.setPassword("1234");
userMapper.add(userInfo);
System.out.println("Method 2 executed");
throw new RuntimeException("Exception in Method 2");
}
}
package org.example.springboottransaction.controller;
import org.example.springboottransaction.service.TransactionService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class TransactionClient {
@Autowired
private TransactionService transactionService;
@GetMapping("/transaction")
public String performTransactions() {
transactionService.transactionMethod1();
transactionService.transactionMethod2();
return "OK";
}
}
在上述代码中,performTransactions
方法依次调用了两个事务方法。请注意,transactionMethod2
方法抛出了运行时异常。
由于默认的事务传播行为是 PROPAGATION_REQUIRED
,整个事务会回滚,包括前面已经执行的 transactionMethod1
。
查看数据库表,会发现一条数据也没有插入。
我们修改 transactionMethod2
方法的事务传播机制为 PROPAGATION_REQUIRES_NEW
,让它新建一个事务,不要影响 transactionMethod1
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void transactionMethod2() {
// 另一些业务逻辑...
UserInfo userInfo = new UserInfo();
userInfo.setUsername("LiSi");
userInfo.setPassword("1234");
userMapper.add(userInfo);
System.out.println("Method 2 executed");
throw new RuntimeException("Exception in Method 2");
}
重新调用 performTransactions
方法,查看数据库表,会发现 transactionMethod1
执行的数据成功插入了。
嵌套事务(NESTED)和加入事务(REQUIRED)的区别