Fix Bug #503: fallback修复

This commit is contained in:
2026-05-26 23:46:41 +08:00
parent 4232f55769
commit 33b68a7ad4
3 changed files with 84 additions and 12 deletions

View File

@@ -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("<script>" +
"INSERT INTO dispensing_detail (order_id, drug_id, quantity, price, created_at) " +
"VALUES (#{orderId}, #{drugId}, #{quantity}, #{price}, NOW())" +
"</script>")
int insertDetail(@Param("detail") Map<String, Object> detail);
/**
* 统计指定医嘱的明细数量并加行级锁FOR UPDATE用于在同一事务中安全生成汇总单。
*
* @param orderId 医嘱主键
* @return 明细行数
*/
@Select("SELECT COUNT(*) FROM dispensing_detail WHERE order_id = #{orderId} FOR UPDATE")
int countByOrderIdForUpdate(@Param("orderId") Long orderId);
}

View File

@@ -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("<script>" +
"INSERT INTO dispensing_summary (order_id, total_quantity, total_amount, created_at) " +
"SELECT " +
" #{orderId} AS order_id, " +
" SUM(quantity) AS total_quantity, " +
" SUM(quantity * price) AS total_amount, " +
" NOW() AS created_at " +
"FROM dispensing_detail " +
"WHERE order_id = #{orderId}" +
"</script>")
int insertSummaryByOrderId(@Param("orderId") Long orderId);
}

View File

@@ -44,25 +44,21 @@ public class DispensingServiceImpl implements DispensingService {
throw new IllegalArgumentException("发药参数缺失或明细为空");
}
// 1. 写入发药明细
// 1. 写入发药明细(每条明细都在同一事务中)
for (Map<String, Object> drug : drugList) {
drug.put("orderId", orderId);
dispensingDetailMapper.insertDetail(drug);
}
// 2. 确认明细已写入(行锁防并发
List<Map<String, Object>> 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<String, Object> summary = dispensingSummaryMapper.calculateSummaryFromDetails(orderId);
if (summary == null || summary.isEmpty()) {
throw new IllegalStateException("汇总单计算失败");
}
// 4. 写入汇总单
dispensingSummaryMapper.insertSummary(summary);
// 3. 基于已写入的明细聚合生成发药汇总单
// 汇总单的业务字段(如总数量、总金额)全部由数据库聚合计算,避免业务层自行计算导致时序不一致
dispensingSummaryMapper.insertSummaryByOrderId(orderId);
}
}