Spring Boot中支付方式实体无法同步已确认发票信息的问题排查
问题描述
开发Spring Boot应用时,需要在发票确认后将已确认发票信息更新至支付方式实体(如CardEntity、CashEntity)。目前PaymentEntity能正确关联已确认发票,但CardEntity的confirmInvoiceEntity字段始终无法更新,尝试两种实现方式均无效。
现有代码实现
CardEntity.java
@Entity @Table(name = "card_tbl") public class CardEntity { @Id private Long cardRefNo; private Double paidAmount; private Date paidDate; private Long paymentId; @ManyToOne(fetch = FetchType.LAZY) @JoinColumn(name = "tempInvoiceId") private TempInvoiceEntity tempInvoiceEntity; @ManyToOne(fetch = FetchType.LAZY) @JoinColumn(name = "confirmInvoiceId") private ConfirmInvoiceEntity confirmInvoiceEntity; // Getters and Setters }
CardRepo.java
@Repository public interface CardRepo extends JpaRepository<CardEntity, Long> { List<CardEntity> findByTempInvoiceEntity_TempInvoiceId(Long tempInvoiceId); }
第一种实现:ConfirmInvoiceServiceImple.java
@Service @RequiredArgsConstructor public class ConfirmInvoiceServiceImple implements ConfirmInvoiceService { private final TempInvoiceRepo tempInvoiceRepo; private final ConfirmInvoiceRepo confirmInvoiceRepo; private final ConfirmProductCartService confirmProductCartService; private final PaymentsRepo paymentsRepo; private final CardRepo cardRepo; private final CashRepo cashRepo; private final ChequeRepo chequeRepo; @Override @Transactional public NonPaginatedResponse insertIntoConfirmInvoice(Long invoiceId) { NonPaginatedResponse response = new NonPaginatedResponse(); try { TempInvoiceEntity selectedTempInvoice = tempInvoiceRepo.findById(invoiceId).get(); ConfirmInvoiceEntity confirmedInvoice = createNewConfirmInvoiceData(selectedTempInvoice); Boolean isCartItemsConfirmed = confirmProductCartService.confirmTheCartItems(invoiceId, confirmedInvoice); if (isCartItemsConfirmed) { List<PaymentsEntity> selectAllPayments = paymentsRepo.findBySalesInvoice_TempInvoiceId(confirmedInvoice.getConfirmInvoiceId()); List<PaymentsEntity> listOfPayments = selectAllPayments.stream().map( payment -> { PaymentsEntity aPay = new PaymentsEntity(); aPay.setPaymentType(payment.getPaymentType()); aPay.setPaidDate(payment.getPaidDate()); aPay.setPaidAmount(payment.getPaidAmount()); aPay.setConfirmInvoice(confirmedInvoice); aPay.setSalesInvoice(null); alterPaymentMethConfirmInvoice(payment, confirmedInvoice); return aPay; } ).toList(); paymentsRepo.saveAll(listOfPayments); tempInvoiceRepo.deleteById(confirmedInvoice.getConfirmInvoiceId()); } response.setStatus(HttpStatus.ACCEPTED); response.setSuccessMessage("Invoice has been confirmed."); response.setResult(null); } catch (Exception e) { e.printStackTrace(); response.setErrors(Collections.singletonList("Couldn't confirm the selected invoice")); response.setStatus(HttpStatus.BAD_GATEWAY); } return response; } public void alterPaymentMethConfirmInvoice(PaymentsEntity payment, ConfirmInvoiceEntity confirmedInvoice) { if (payment.getPaymentType().equalsIgnoreCase("card")) { List<CardEntity> cardEntities = cardRepo.findByTempInvoiceEntity_TempInvoiceId(payment.getPaymentId()); for (CardEntity cardEntity : cardEntities) { cardEntity.setConfirmInvoiceEntity(confirmedInvoice); } cardRepo.saveAll(cardEntities); } } private ConfirmInvoiceEntity createNewConfirmInvoiceData(TempInvoiceEntity tempInvoiceEntity) { ConfirmInvoiceEntity confirmInvoiceEntity = new ConfirmInvoiceEntity(); confirmInvoiceEntity.setConfirmInvoiceId(tempInvoiceEntity.getTempInvoiceId()); confirmInvoiceEntity.setInvoiceNumber(tempInvoiceEntity.getTempInvoiceNumber()); confirmInvoiceEntity.setDate(new Date()); confirmInvoiceEntity.setPaidAmount(tempInvoiceEntity.getPaidAmount()); confirmInvoiceEntity.setNetAmount(tempInvoiceEntity.getNetAmount()); confirmInvoiceEntity.setCustomer(tempInvoiceEntity.getCustomer()); return confirmInvoiceRepo.save(confirmInvoiceEntity); } }
第二种尝试的实现(修改后的核心方法)
@Override @Transactional public NonPaginatedResponse insertIntoConfirmInvoice(Long invoiceId) { NonPaginatedResponse response = new NonPaginatedResponse(); try { TempInvoiceEntity selectedTempInvoice = tempInvoiceRepo.findById(invoiceId).get(); ConfirmInvoiceEntity confirmedInvoice = createNewConfirmInvoiceData(selectedTempInvoice); Boolean isCartItemsConfirmed = confirmProductCartService.confirmTheCartItems(invoiceId, confirmedInvoice); if (isCartItemsConfirmed) { List<PaymentsEntity> selectAllPayments = paymentsRepo.findBySalesInvoice_TempInvoiceId(confirmedInvoice.getConfirmInvoiceId()); alterPaymentMethConfirmInvoice(selectAllPayments, confirmedInvoice); List<PaymentsEntity> listOfPayments = selectAllPayments.stream().map( payment -> { PaymentsEntity aPay = new PaymentsEntity(); aPay.setPaymentType(payment.getPaymentType()); aPay.setPaidDate(payment.getPaidDate()); aPay.setPaidAmount(payment.getPaidAmount()); aPay.setConfirmInvoice(confirmedInvoice); aPay.setSalesInvoice(null); return aPay; } ).toList(); paymentsRepo.saveAll(listOfPayments); tempInvoiceRepo.deleteById(confirmedInvoice.getConfirmInvoiceId()); } response.setStatus(HttpStatus.ACCEPTED); response.setSuccessMessage(ConfirmInvoiceConsonants.INVOICE_HAS_BEEN_CONFIRMED); response.setResult(null); } catch (Exception e) { e.printStackTrace(); response.setErrors(Arrays.asList("Couldn't Confirm the selected invoice")); response.setStatus(HttpStatus.BAD_GATEWAY); } return response; } public void alterPaymentMethConfirmInvoice(List<PaymentsEntity> selectAllPayments, ConfirmInvoiceEntity confirmedInvoice) { selectAllPayments.stream().filter( allPay->{ if (allPay.getPaymentType().equalsIgnoreCase("card")) { List<CardEntity> cardEntities = cardRepo.findByTempInvoiceEntity_TempInvoiceId(confirmedInvoice.getConfirmInvoiceId()); for (CardEntity cardEntity : cardEntities) { cardEntity.setConfirmInvoiceEntity(confirmedInvoice); } cardRepo.saveAll(cardEntities); } return false; } ).toList(); }
问题原因分析及解决方案
核心问题1:查询条件错误(第一种实现)
第一种实现的alterPaymentMethConfirmInvoice方法中,使用payment.getPaymentId()作为参数调用cardRepo.findByTempInvoiceEntity_TempInvoiceId(),属于逻辑错误:
payment.getPaymentId()是支付记录的ID,而findByTempInvoiceEntity_TempInvoiceId()需要的是临时发票ID,两者语义完全不同,导致查询不到对应的CardEntity,自然无法更新。
修复方案:
使用当前确认的发票对应的原临时发票ID(即传入的invoiceId)作为查询参数:
public void alterPaymentMethConfirmInvoice(PaymentsEntity payment, ConfirmInvoiceEntity confirmedInvoice, Long originalTempInvoiceId) { if (payment.getPaymentType().equalsIgnoreCase("card")) { // 使用原临时发票ID查询关联的CardEntity List<CardEntity> cardEntities = cardRepo.findByTempInvoiceEntity_TempInvoiceId(originalTempInvoiceId); for (CardEntity cardEntity : cardEntities) { cardEntity.setConfirmInvoiceEntity(confirmedInvoice); } cardRepo.saveAll(cardEntities); } }
调用时传入invoiceId:
alterPaymentMethConfirmInvoice(payment, confirmedInvoice, invoiceId);
核心问题2:Stream API使用错误(第二种实现)
第二种实现的alterPaymentMethConfirmInvoice方法中,将业务逻辑写在filter()里且返回false:
- Stream的
filter()用于过滤元素,只有返回true的元素才会进入后续操作;结合Stream的惰性求值特性,当所有元素都返回false时,内部的更新代码根本不会执行。
修复方案:
将filter()改为forEach(),专门用于执行更新操作:
public void alterPaymentMethConfirmInvoice(List<PaymentsEntity> selectAllPayments, ConfirmInvoiceEntity confirmedInvoice, Long originalTempInvoiceId) { selectAllPayments.stream() .filter(allPay -> allPay.getPaymentType().equalsIgnoreCase("card")) .forEach(allPay -> { List<CardEntity> cardEntities = cardRepo.findByTempInvoiceEntity_TempInvoiceId(originalTempInvoiceId); for (CardEntity cardEntity : cardEntities) { cardEntity.setConfirmInvoiceEntity(confirmedInvoice); } cardRepo.saveAll(cardEntities); }); }
同时传入正确的originalTempInvoiceId(即invoiceId)。
额外注意点
- 事务一致性:确保所有更新操作都在同一个事务中(当前方法已标注
@Transactional,满足要求)。 - Lazy加载问题:如果
TempInvoiceEntity是懒加载,查询CardEntity时确保会话未关闭(事务内操作不会有此问题)。 - 主键冲突验证:确认
ConfirmInvoiceEntity的confirmInvoiceId设置正确(当前复用原临时发票ID,需确保无主键冲突)。
内容的提问来源于stack exchange,提问作者Kabil
相关产品推荐
相关产品推荐

