通过/exist接口编辑预订后实体「消失」问题排查与修复咨询
问题:预订编辑后「自行消失」但数据库仍存在,字段无法修改
问题现象
- 创建预订后调用
/exist接口编辑,业务层面出现预订「自行消失」的情况,但通过MySQL查询确认Reservation实体仍存在于数据库中 - 调试过程无错误提示,无法将原本非null的字段从null状态修改回来
相关控制器代码
@PostMapping("/exist") public ResponseEntity createreservationExist(@RequestBody Map<Object, Object> payLoad ) throws URISyntaxException, ParseException { long id=(Integer)payLoad.get("id"); Reservation reservation=reservationServices.getreservationById(id); String creditCardNumber=""; creditCardNumber=(String)payLoad.get("creditCardNumber"); String note=(String)payLoad.get("note"); reservation.setNote(note); DateFormat simpleDateFormat=new SimpleDateFormat("yyyy-MM-dd"); java.util.Date utilDate=simpleDateFormat.parse((String)payLoad.get("dateOfEvent")); Date ofDate=new java.sql.Date(utilDate.getTime()); reservation.setName((String)payLoad.get("name")); reservation.setDateOfEvent(ofDate); ArrayList<Order> orders=new ArrayList<>(reservation.getOrders()); double total=0; double tax=0.15; for(int i=0;i<orders.size();i++){ total+=foodServices.getFoodByName(orders.get(i).getFood()).getPrice()*orders.get(i).getQuantity(); } total=total+(total*tax); total=(total * 100) / 100.0; Transaction transaction=new Transaction(creditCardNumber,total,reservation); try{ transactionServices.removetransaction(reservation.getTransaction().getId());} catch(Exception e){ } reservation.setTransaction(transaction); reservationServices.saveReservation(reservation); return ResponseEntity.ok().build(); }
原因分析
- 异常被静默吞掉:删除旧
Transaction的try/catch块未做任何处理,若旧交易记录不存在或删除失败,异常被隐藏,后续关联新交易的逻辑可能出现问题,导致预订关联数据异常,业务层面无法正常查询到预订 - 实体持久化状态异常:如果
reservationServices.getreservationById(id)获取的实体脱离了当前持久化上下文(比如查询使用了只读事务或查询后上下文关闭),修改字段后调用saveReservation可能无法触发数据库更新,导致字段修改不生效 - 字段赋值无null校验:从
payLoad中获取的name、note等字段如果为null,会直接覆盖原有非null值,导致字段被设为null,业务层面误判预订“消失” - 日期转换无异常处理:
SimpleDateFormat.parse若传入无效日期格式会抛出ParseException,但控制器直接抛出未做处理,可能导致请求中断但无明确反馈,表现为预订编辑后“消失”
修复方法
移除异常静默处理,添加错误日志与反馈
删除空catch块,改为记录错误日志并抛出明确异常,确保问题可追踪:try { transactionServices.removetransaction(reservation.getTransaction().getId()); } catch(Exception e) { log.error("删除旧交易记录失败,预订ID: {}", id, e); throw new RuntimeException("更新预订失败:无法删除旧交易记录"); }确保实体处于持久化上下文
检查reservationServices.getreservationById的实现,确保查询在事务上下文内;若使用JPA,修改后调用merge方法确保实体状态同步到数据库:// 修改后合并实体到持久化上下文 reservation = reservationServices.mergeReservation(reservation);或在
saveReservation方法中使用entityManager.merge(reservation)替代persist添加字段null校验,保留原有值
从payLoad取值时判断是否为null,仅在非null时覆盖原有字段值:String note = (String) payLoad.get("note"); if (note != null) { reservation.setNote(note); } String name = (String) payLoad.get("name"); if (name != null) { reservation.setName(name); }完善日期转换的异常处理
对日期解析添加异常捕获,返回明确的错误响应:Date ofDate; try { DateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd"); java.util.Date utilDate = simpleDateFormat.parse((String) payLoad.get("dateOfEvent")); ofDate = new java.sql.Date(utilDate.getTime()); reservation.setDateOfEvent(ofDate); } catch (ParseException e) { log.error("日期格式错误,传入值: {}", payLoad.get("dateOfEvent"), e); return ResponseEntity.badRequest().body("日期格式错误,请使用yyyy-MM-dd格式"); }检查实体关联配置
确认Reservation与Transaction的关联注解(如@OneToOne)配置正确,级联规则符合业务逻辑,避免因关联失败导致业务查询无法获取预订
内容的提问来源于stack exchange,提问作者livecode
相关产品推荐
相关产品推荐

