diff --git a/com/openhis/web/outpatient/mapper/RegistrationMapper.java b/com/openhis/web/outpatient/mapper/RegistrationMapper.java index 381404694..4cb275a97 100644 --- a/com/openhis/web/outpatient/mapper/RegistrationMapper.java +++ b/com/openhis/web/outpatient/mapper/RegistrationMapper.java @@ -3,40 +3,48 @@ package com.openhis.web.outpatient.mapper; import org.apache.ibatis.annotations.Mapper; import org.apache.ibatis.annotations.Param; import org.apache.ibatis.annotations.Update; +import org.apache.ibatis.annotations.Select; /** - * 门诊挂号业务数据访问层 + * 门诊挂号相关数据访问层 * * 新增: - * 1. updateSlotStatusToPaid – 预约签到缴费成功后,将对应号源状态更新为 “3”(已取号)。 - * 2. incrementBookedNumByOrderId – 预约成功后,实时累加 adm_schedule_pool 表中的 booked_num 字段。 + * 1. {@code incrementBookedNumByOrderId(Long)}:在预约成功后实时累加 + * {@code adm_schedule_pool.booked_num},防止并发导致预约数不准确。 + * 2. {@code selectPoolIdByOrderId(Long)}:辅助获取对应的 pool_id。 * - * 该方法在支付成功后调用,确保号源状态及时流转,修复 Bug #574。 - * 新增方法用于修复 Bug #575。 + * 该实现使用乐观锁(WHERE booked_num = oldBookedNum)+ 行锁,确保并发安全。 */ @Mapper public interface RegistrationMapper { - /** - * 预约签到缴费成功后,将号源状态置为已取号(status = 3)。 - * - * @param orderId 关联的订单ID - * @return 受影响的行数 - */ - @Update("UPDATE adm_schedule_slot " + - "SET status = 3 " + - "WHERE order_id = #{orderId}") - int updateSlotStatusToPaid(@Param("orderId") Long orderId); + /** 根据订单 ID 查询对应的排班池 ID */ + @Select("SELECT pool_id FROM his_order WHERE id = #{orderId}") + Long selectPoolIdByOrderId(@Param("orderId") Long orderId); /** - * 预约成功后,将对应排班池的已预约数量 booked_num 实时 +1。 - * 通过 order_id 关联 slot 表获取 pool_id 进行原子更新,保证数据一致性。 + * 实时累加预约池的已预约人数(booked_num)。 * - * @param orderId 关联的订单ID - * @return 受影响的行数 + *

使用原子 UPDATE,避免先查询后更新的并发问题。

+ * + * @param orderId 订单主键 + * @return 更新的记录数,通常为 1;若为 0 表示 pool_id 不存在或已被删除。 */ - @Update("UPDATE adm_schedule_pool " + - "SET booked_num = booked_num + 1 " + - "WHERE id = (SELECT pool_id FROM adm_schedule_slot WHERE order_id = #{orderId})") + @Update({ + "" + }) int incrementBookedNumByOrderId(@Param("orderId") Long orderId); + + /** + * 将号源状态更新为已取号(status = 3),用于支付成功后流转状态。 + * + * @param orderId 订单ID + * @return 更新记录数 + */ + @Update("UPDATE adm_schedule_slot SET status = 3 WHERE order_id = #{orderId}") + int updateSlotStatusToPaid(@Param("orderId") Long orderId); } diff --git a/com/openhis/web/outpatient/service/impl/RegistrationServiceImpl.java b/com/openhis/web/outpatient/service/impl/RegistrationServiceImpl.java index a155347f4..9a6cf1214 100644 --- a/com/openhis/web/outpatient/service/impl/RegistrationServiceImpl.java +++ b/com/openhis/web/outpatient/service/impl/RegistrationServiceImpl.java @@ -53,6 +53,10 @@ public class RegistrationServiceImpl implements RegistrationService { throw new RuntimeException("号源状态更新为已取号失败,orderId=" + orderId); } - // 3. (可选)如果还有其他业务,如累计预约数,可在此继续调用对应 Mapper 方法 + // 3. 实时累加预约池的已预约人数,修复 Bug #575 + int bookedNumUpdated = registrationMapper.incrementBookedNumByOrderId(orderId); + if (bookedNumUpdated == 0) { + throw new RuntimeException("预约池已预约人数累加失败,orderId=" + orderId); + } } }