今天找了一个之前小伙伴写的bug代码,大致内容如下:
try {
System.out.println("调用接口处理开始");
feePersonAdd=this.feePerson(null, null, prpSverifyDetail.getVerifyType(), userCodeStr);//主要是保存报文操作
System.out.println("调用口处理结束");
} catch (Exception e) {
e.printStackTrace();
}
if(!feePersonAdd){
throw new BusinessException("任务预处理时发生异常。调用接口失败。", false);
}
可以看到在进行一系列操作之后,如果出现异常,则最后执行 throw new BusinessException("任务预处理时发生异常。调用接口失败。", false); 这就导致会将失败的报文丢失掉,最终结果是,如果调用成功,则报文可以正常保存,如果调用失败,则报文丢失,为什么为造成这样的现象呢?
那是因为在写代码的时候没有考虑到Spring的事物机制,默认spring事务只在发生未被捕获的 runtimeexcetpion时才回滚,而BusinessException类是继承了RuntimeException 。
如果使用声明式事务管理,@Transactional,默认情况下所有的RuntimeException会触发回滚,所有的checked Exception不会触发回滚,可以通过rollback-for和no-rollback-for来调整配置,如果单单只是 catch异常,没有抛出,则异常没办法到事务管理器中,不会触发回滚操作。简单点可以理解为:使用 throw RuntimeException 则事务会回滚。
针对以上代码,解决方案为重新申明一个session事务,用来单独提交保存报文这个事务:
Session session = super.getHibernateTemplate().getSessionFactory().openSession();
Transaction transaction = session.beginTransaction();
session.saveOrUpdate(xmlMessage);
transaction.commit();
session.close();
在开发过程中常见的RuntimeException类型的异常主要有以下几种:
ArithmeticException:数学计算异常。
NullPointerException:空指针异常。
NegativeArraySizeException:负数组长度异常。
ArrayOutOfBoundsException:数组索引越界异常。
ClassNotFoundException:类文件未找到异常。
ClassCastException:类型强制转换异常。
SecurityException:违背安全原则异常。
IllegalArgumentException- 传递非法参数异常
ArrayStoreException - 向数组中存放与声明类型不兼容对象异常
IndexOutOfBoundsException - 下标越界异常
NumberFormatException - 数字格式异常
UnsupportedOperationException - 不支持的操作异常
其他非RuntimeException类型的常见异常主要有以下几种:
NoSuchMethodException:方法未找到异常。
IOException:输入输出异常。
EOFException:文件已结束异常。
FileNotFoundException:文件未找到异常。
NumberFormatException:字符串转换为数字异常。
SQLException:操作数据库异常