面试题答案
一键面试确保事务正确回滚
- 默认回滚规则:在Spring Boot中,默认情况下,运行时异常(
RuntimeException
及其子类)和错误(Error
)会触发事务回滚。如果业务方法抛出这类异常,Spring的事务管理器会自动回滚事务。例如:
@Service
public class UserService {
@Autowired
private UserRepository userRepository;
@Transactional
public void addUser(User user) {
userRepository.save(user);
if (user.getAge() < 0) {
throw new IllegalArgumentException("年龄不能为负数");
}
}
}
这里IllegalArgumentException
是运行时异常,当抛出该异常时,事务会回滚。
2. 自定义回滚规则:如果希望受检异常(Checked Exception
)也触发事务回滚,可以在@Transactional
注解中使用rollbackFor
属性。例如:
@Transactional(rollbackFor = {SQLException.class})
public void customRollback() throws SQLException {
// 数据库操作
throw new SQLException("自定义数据库异常");
}
这样当SQLException
抛出时,事务也会回滚。
嵌套事务内层异常时外层事务的处理
- PROPAGATION_REQUIRED(默认):如果内层事务使用
PROPAGATION_REQUIRED
传播行为(这是Spring事务的默认传播行为),内层事务实际上是加入到外层事务中,成为一个整体。当内层事务抛出异常时,外层事务也会回滚。例如:
@Service
public class OuterService {
@Autowired
private InnerService innerService;
@Transactional
public void outerMethod() {
try {
innerService.innerMethod();
} catch (Exception e) {
// 捕获异常但不处理,事务仍会回滚
}
}
}
@Service
public class InnerService {
@Transactional
public void innerMethod() {
// 数据库操作
throw new RuntimeException("内层事务异常");
}
}
这里内层事务抛出RuntimeException
,由于使用默认的PROPAGATION_REQUIRED
,外层事务也会回滚。
2. PROPAGATION_NESTED:当内层事务使用PROPAGATION_NESTED
传播行为时,内层事务是外层事务的一个嵌套子事务。如果内层事务抛出异常并回滚,外层事务可以选择捕获异常并继续执行,也可以选择不捕获让外层事务也回滚。例如:
@Service
public class OuterService {
@Autowired
private InnerService innerService;
@Transactional
public void outerMethod() {
try {
innerService.innerMethod();
} catch (Exception e) {
// 捕获内层异常,外层事务可以继续执行
// 例如进行一些补偿操作
}
}
}
@Service
public class InnerService {
@Transactional(propagation = Propagation.NESTED)
public void innerMethod() {
// 数据库操作
throw new RuntimeException("内层事务异常");
}
}
这里外层事务捕获内层事务异常后,外层事务可以继续执行,不会整体回滚。
异常处理机制与事务管理机制协同工作
- 事务切面:Spring通过AOP(面向切面编程)实现事务管理,将事务管理逻辑封装在切面中。当方法被调用时,事务切面会在方法执行前后进行事务相关操作,如开启事务、提交事务或回滚事务。
- 异常捕获与传播:当业务方法抛出异常时,事务切面会捕获异常。如果异常满足回滚条件(如运行时异常或自定义回滚规则中的异常),事务切面会触发事务回滚。如果异常不满足回滚条件,事务切面会继续传播异常,由上层调用者处理。例如,在一个
Controller
调用Service
方法时:
@RestController
public class UserController {
@Autowired
private UserService userService;
@GetMapping("/addUser")
public String addUser(User user) {
try {
userService.addUser(user);
return "用户添加成功";
} catch (Exception e) {
return "用户添加失败: " + e.getMessage();
}
}
}
这里UserService
中的addUser
方法抛出异常,UserController
捕获异常并返回错误信息,同时事务切面已经根据异常情况决定是否回滚事务。
可能遇到的问题及解决方案
- 异常未正确触发回滚:可能是因为抛出的是受检异常且未设置
rollbackFor
属性。解决方案是设置rollbackFor
属性或者将受检异常转换为运行时异常。 - 嵌套事务行为不符合预期:可能是传播行为设置错误。检查内层事务和外层事务的传播行为是否符合业务需求,如确保
PROPAGATION_NESTED
行为的正确使用。 - 事务切面未生效:可能是因为类没有被Spring容器管理,或者AOP配置有问题。确保相关类被正确标注为
@Component
、@Service
等,并且AOP配置正确。例如,检查spring - aop
依赖是否正确引入,以及是否配置了@EnableAspectJAutoProxy
注解。