Java 的异常类图结构
两种异常的分类方式:
第一种:运行时异常(RuntimeException)、非运行时异常 (Exception 下除了RuntimeException及其子类的其他异常)
第二种:受检异常(非运行时异常)、非受检异常(RuntimeException和Error)
Spring @Transactional 注解的作用
@Transactional 是Spring框架的事务管理,作用是如果业务对数据库操作出现异常的情况下可以回滚数据库操作。
Spring框架的事务管理默认是只在发生不受控异常(RuntimeException和Error)时才进行事务回滚。
实际上是Spring 会把Error 转化成 RuntimeException 从而进行事务回滚。
当业务操作中发生了受检异常(即Exception 下除了RuntimeException及其子类的其他异常)时不会进行事务回滚。
rollbackFor 属性介绍
在实际开发中我们是希望发生任何异常都要发生回滚操作,即在发生受检异常的情况下也要进行事务回滚,默认情况下@Transactional 的不足:在发生受检异常时(Exception 下除了RuntimeException及其子类的其他异常)不会回滚。
解决办法:在@Transactional 注解中增加 rollbackFor 设置rollbackFor 属性值。
即:@Transactional(rollbackFor = Exception.class)
@Transactional 注解的全部属性详解
属性 | 类型 | 描述 |
---|---|---|
value | String | 可选的限定描述符,指定使用的事务管理器 |
propagation | enum: Propagation | 可选的事务传播行为设置 |
isolation | enum: Isolation | 可选的事务隔离级别设置 |
readOnly | boolean | 读写或只读事务,默认读写 |
timeout | int (in seconds granularity) | 事务超时时间设置 |
rollbackFor | Class对象数组,必须继承自Throwable | 导致事务回滚的异常类数组 |
rollbackForClassName | 类名数组,必须继承自Throwable | 导致事务回滚的异常类名字数组 |
noRollbackFor | Class对象数组,必须继承自Throwable | 不会导致事务回滚的异常类数组 |
noRollbackForClassName | 类名数组,必须继承自Throwable | 不会导致事务回滚的异常类名字数组 |
rollbackFor使用
@Transactional
的rollbackFor用于指定能够触发事务回滚的异常类型,可以指定多个,用逗号分隔。
rollbackFor
默认值为UncheckedException,包括了RuntimeException和Error.
当我们直接使用@Transactional
不指定rollbackFor
时,Exception及其子类都不会触发回滚。
public class BusinessException extends Exception {
public BusinessException(String msg) {
super(msg);
}
}
各种情况的测试:
@Autowired
private UserRepository userRepository;
// 不回滚
@Transactional
public void test1() throws Exception {
User user = new User(1, "15000000000", "d243ewa", "Comma");
saveUser(user);
throw new Exception("test1 error");
}
// 不回滚
@Transactional
public void test11() throws Exception {
User user = new User(1, "15000000000", "d243ewa", "Comma");
saveUser(user);
throw new BusinessException("test11 error");
}
// 回滚
@Transactional(rollbackFor = Exception.class)
public void test2() throws Exception {
User user = new User(1, "15000000000", "d243ewa", "Comma");
saveUser(user);
throw new Exception("test2 error");
}
// 回滚
@Transactional(rollbackFor = Exception.class)
public void test21() throws Exception {
User user = new User(1, "15000000000", "d243ewa", "Comma");
saveUser(user);
throw new BusinessException("test21 error");
}
// 回滚
@Transactional
public void test3() {
User user = new User(1, "15000000000", "d243ewa", "Comma");
saveUser(user);
throw new RuntimeException("test3 runtime error");
}
// 不回滚
@Transactional
public void test4() throws Exception {
User user = new User(1, "15000000000", "d243ewa", "Comma");
test41(user);
throw new Exception("test4 error");
}
@Transactional(rollbackFor = Exception.class)
public void test41(User user) {
saveUser(user);
}
// 不回滚
public void test5() throws BusinessException {
test6();
}
// 回滚
@Transactional(rollbackFor = Exception.class)
public void test6() throws BusinessException {
User user = new User(1, "15000000000", "d243ewa", "Comma");
saveUser(user);
throw new BusinessException("test6 error");
}
// 回滚
@Transactional(rollbackFor = Exception.class)
public void test7() throws BusinessException {
test8();
}
public void test8() throws BusinessException {
User user = new User(1, "15000000000", "d243ewa", "Comma");
saveUser(user);
throw new BusinessException("test8 error");
}
public User saveUser(User user) {
return userRepository.save(user);
}