在《Effecitive Java》中,作者提出过,不建议使用异常来控制业务流程。很多人 不理解,啥叫用异常控制业务流程。
给大家举个简单的例子,在解决幂等问题时,我们有的人会这么做,先插入,然后再捕获唯一性约束冲突异常,再反查,返回幂等。如:
public void insertData(Data data) {
try {
// 尝试插入数据
dataRepository.insert(data);
} catch (DuplicateKeyException e) {
// 捕获唯一性约束冲突异常
Data existingData = dataRepository.findByUniqueKey(data.getUniqueKey());
// 返回已存在的数据,以实现幂等性
return existingData;
}
}
这么做非常不建议,主要由以下几个问题:
1、存在性能问题:在Java中,异常的生成和处理是昂贵的,因为它涉及到填充栈跟踪信息。频繁地抛出和捕获异常会导致性能下降。
2、异常的职责就不是干这个的:Java中的异常被定义来处理一些非正常情况的,他的使用应该是比较谨慎的,异常应该用于处理非预期的错误情况,而不是利用它来控制正常的业务流程。使用异常控制业务流程会使代码的意图变得不清晰,增加了理解和维护代码的难度。
3、异常的捕获会影响事务的回滚:这里代码很简单,可能不涉及到事务,但是如果本身这个方法还有很多其他的数据库操作逻辑,或者方法外嵌套了一层方法,那么就会可能会出现,因为异常被捕获而导致的事务无法回滚。
4、过度依赖底层数据库异常:这里过度的依赖了DuplicateKeyException,万一哪一天这个异常发生了改变,比如版本升级了,或者底层数据库变了,不再抛出这个异常了,那这段代码就会失去作用,可能会导致意想不到的问题。
还有一点,那就是良好的API设计应该清晰地表达意图。如果API使用异常来表示常规的业务流程控制,这可能会误导API的使用者,使他们误解API的真正用途。
所以,不建议大家过度的使用异常,并且非常不建议使用异常来控制你的业务流程。
前面提到的幂等问题,要解决幂等问题,应该是先查,再改。如果为了防止并发,应该是一锁、二判、三更新。