Spring Boot JPA save方法之怪异
项目场景
工作中的一个小需求,由于这个项目第一阶段只是引入,作为触发程序在后台跑数据,将下游的数据引入即可。所以不需要暴露在页面上。所以报错的话,是没有任何人感知的。所以需要提供一个监控程序,就是在遇到异常就记录下来,每日满足发生5次异常就发送邮件通知,通知后就不再通知。
问题描述
程序其实很简单,但是测试Demo的时候,由于使用的是
JPA
,使用的save
方法保存,方法内部处理就是先判断isNew
,然后去做update
或者insert
操作。问题是这个方法遇到数据库异常,比如主键冲突,虽然打印日志,但是异常实际上是被某个异常处理器处理掉了,根本报不出来。
java
try{
dao.save(entity);
}catch (Exception e) {
log.error("error happened", e);
monitorExceptionService.recordError(e);
}
这个错误日志是进入不到catch
里面的。
问题原因
网上资料介绍要使用
saveAndFlush
方法,查看内部源码,其实就是多了一个flush
方法。flush
其实就是将sql预编译执行的结果发送给数据库得到的结果。save方法是在sql
统一提交的才会报错,就是@Transactional
整体结束的时候报错,所以catch
不到报错。而saveAndFlush
方法多的flush
方法就是将sql
结果发送到数据库,所以立马能得到报错。
源码如下:
java
@Transactional
@Override
public <S extends T> S saveAndFlush(S entity) {
S result = save(entity);
flush();
return result;
}
解决方案
就是将save
方法改为saveAndFlush
方法即可。
代码如下:
java
try{
dao.saveAndFlush(entity);
}catch (Exception e) {
log.error("error happened", e);
monitorExceptionService.recordError(e);
}