下面总结异常不抛出的几种情况:
一、事物回滚默认:运行时异常(RuntimeException)和程序错误(Error)
下面这段代码事务不会回滚:
@Service
public class ProductServiceImpl implements ProductService {
@Resource
private ProductDao productDao ;
@Override
@Transactional
public void insertProduct(Product product) throws Exception {
// 插入产品信息
productDao .insertProduct(product);
// 手动抛出异常
throw new SQLException("数据库异常");
}
}
以上代码数据库插入仍然成功,因为spring boot项目,只有RuntimeException和error时,事物才会回滚。而以上代码跑出的是SQLException,所以插入数据库仍然成功。如果要一切异常都进行回滚,则在类上加下面这句即可:
@Transactional(rollbackFor = Exception.class)
二、try… catch…代码块将异常捕获,使事务不回滚
下面代码是很好的例子:
@Service
public class cityServiceImpl implements cityService {
@Resource
private CityDao cityDao;
@Override
@Transactional(rollbackFor = Exception.class)
public void insertCity(City city) {
try {
// 插入城市信息
cityDao .insertCity(city);
// 手动抛出异常
throw new SQLException("数据库异常");
} catch (Exception e) {
// 异常处理逻辑
}
}
}
因为手动抛出的异常被catch捕获了,所以代码没有执行抛出异常的那句,事务不会回滚。要回滚的方法就是不写catch语句。
三、事务的优先级大于锁的优先级
请看下面这段代码:
@Service
public class CityServiceImpl implements CityService {
@Resource
private CityDao cityDao;
@Override
@Transactional(rollbackFor = Exception.class)
public synchronized void insertCity(City city) {
// 插入操作
cityDao.insertCity(city);
}
}
批量操作时,会发现有重复的数据,一般情况下,已经存在的数据会进行更新,而不会二次插入。原因就在于举个例子:
a和b两条数据完全一样,a进入了插入方法,插入成功后,释放了锁,此时事务还没有结束,b进来调用了插入方法,因为事务没有结束,事务优先级大于锁的优先级,所以会插入两条完全一样的数据。
解决方法:一 、去掉事务;二、在外部调用这个CityServiceImpl 时加锁
本文参考了
微信公众号:程序员私房菜