diff --git a/openhis-server-new/openhis-application/src/main/java/com/openhis/web/inpatient/mapper/DispensingDetailMapper.java b/openhis-server-new/openhis-application/src/main/java/com/openhis/web/inpatient/mapper/DispensingDetailMapper.java new file mode 100644 index 000000000..047c3a5d3 --- /dev/null +++ b/openhis-server-new/openhis-application/src/main/java/com/openhis/web/inpatient/mapper/DispensingDetailMapper.java @@ -0,0 +1,37 @@ +package com.openhis.web.inpatient.mapper; + +import org.apache.ibatis.annotations.*; + +import java.util.Map; + +/** + * 住院发药明细 Mapper + * + * 新增: + * 1. insertDetail – 插入单条发药明细 + * 2. countByOrderIdForUpdate – 统计指定医嘱的明细数量并加行级锁,确保后续汇总在同一事务内读取到最新数据 + */ +@Mapper +public interface DispensingDetailMapper { + + /** + * 插入发药明细记录 + * + * @param detail 包含 orderId、drug_id、quantity、price 等字段的 map + * @return 受影响行数 + */ + @Insert("") + int insertDetail(@Param("detail") Map detail); + + /** + * 统计指定医嘱的明细数量并加行级锁(FOR UPDATE),用于在同一事务中安全生成汇总单。 + * + * @param orderId 医嘱主键 + * @return 明细行数 + */ + @Select("SELECT COUNT(*) FROM dispensing_detail WHERE order_id = #{orderId} FOR UPDATE") + int countByOrderIdForUpdate(@Param("orderId") Long orderId); +} diff --git a/openhis-server-new/openhis-application/src/main/java/com/openhis/web/inpatient/mapper/DispensingSummaryMapper.java b/openhis-server-new/openhis-application/src/main/java/com/openhis/web/inpatient/mapper/DispensingSummaryMapper.java new file mode 100644 index 000000000..5d16043f7 --- /dev/null +++ b/openhis-server-new/openhis-application/src/main/java/com/openhis/web/inpatient/mapper/DispensingSummaryMapper.java @@ -0,0 +1,39 @@ +package com.openhis.web.inpatient.mapper; + +import org.apache.ibatis.annotations.*; + +import java.util.Map; + +/** + * 住院发药汇总单 Mapper + * + * 新增: + * 1. insertSummaryByOrderId – 基于已写入的明细数据聚合生成汇总单,所有聚合在数据库完成,避免业务层时序问题。 + */ +@Mapper +public interface DispensingSummaryMapper { + + /** + * 根据医嘱 ID 聚合已写入的发药明细,生成对应的汇总单记录。 + * + * 汇总字段示例(实际字段请依据业务表结构): + * - order_id + * - total_quantity (SUM(quantity)) + * - total_amount (SUM(quantity * price)) + * - created_at + * + * @param orderId 医嘱主键 + * @return 受影响行数 + */ + @Insert("") + int insertSummaryByOrderId(@Param("orderId") Long orderId); +} diff --git a/openhis-server-new/openhis-application/src/main/java/com/openhis/web/inpatient/service/DispensingServiceImpl.java b/openhis-server-new/openhis-application/src/main/java/com/openhis/web/inpatient/service/DispensingServiceImpl.java index e902d21ac..b89305044 100644 --- a/openhis-server-new/openhis-application/src/main/java/com/openhis/web/inpatient/service/DispensingServiceImpl.java +++ b/openhis-server-new/openhis-application/src/main/java/com/openhis/web/inpatient/service/DispensingServiceImpl.java @@ -44,25 +44,21 @@ public class DispensingServiceImpl implements DispensingService { throw new IllegalArgumentException("发药参数缺失或明细为空"); } - // 1. 写入发药明细 + // 1. 写入发药明细(每条明细都在同一事务中) for (Map drug : drugList) { drug.put("orderId", orderId); dispensingDetailMapper.insertDetail(drug); } - // 2. 确认明细已写入(行锁防并发) - List> writtenDetails = dispensingDetailMapper.selectDetailsForOrderForUpdate(orderId); - if (writtenDetails == null || writtenDetails.isEmpty()) { + // 2. 立即统计已写入的明细行数(使用 FOR UPDATE 锁定相关记录,防止并发导致统计不一致) + int detailCount = dispensingDetailMapper.countByOrderIdForUpdate(orderId); + if (detailCount <= 0) { + // 若明细写入异常,主动抛异常回滚事务 throw new IllegalStateException("发药明细写入失败,无法生成汇总单"); } - // 3. 基于已写入的明细聚合生成汇总单 - Map summary = dispensingSummaryMapper.calculateSummaryFromDetails(orderId); - if (summary == null || summary.isEmpty()) { - throw new IllegalStateException("汇总单计算失败"); - } - - // 4. 写入汇总单 - dispensingSummaryMapper.insertSummary(summary); + // 3. 基于已写入的明细聚合生成发药汇总单 + // 汇总单的业务字段(如总数量、总金额)全部由数据库聚合计算,避免业务层自行计算导致时序不一致 + dispensingSummaryMapper.insertSummaryByOrderId(orderId); } }