Fix Bug #503: fallback修复
This commit is contained in:
@@ -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);
|
||||||
|
}
|
||||||
@@ -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);
|
||||||
|
}
|
||||||
@@ -44,25 +44,21 @@ public class DispensingServiceImpl implements DispensingService {
|
|||||||
throw new IllegalArgumentException("发药参数缺失或明细为空");
|
throw new IllegalArgumentException("发药参数缺失或明细为空");
|
||||||
}
|
}
|
||||||
|
|
||||||
// 1. 写入发药明细
|
// 1. 写入发药明细(每条明细都在同一事务中)
|
||||||
for (Map<String, Object> drug : drugList) {
|
for (Map<String, Object> drug : drugList) {
|
||||||
drug.put("orderId", orderId);
|
drug.put("orderId", orderId);
|
||||||
dispensingDetailMapper.insertDetail(drug);
|
dispensingDetailMapper.insertDetail(drug);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 2. 确认明细已写入(行锁防并发)
|
// 2. 立即统计已写入的明细行数(使用 FOR UPDATE 锁定相关记录,防止并发导致统计不一致)
|
||||||
List<Map<String, Object>> writtenDetails = dispensingDetailMapper.selectDetailsForOrderForUpdate(orderId);
|
int detailCount = dispensingDetailMapper.countByOrderIdForUpdate(orderId);
|
||||||
if (writtenDetails == null || writtenDetails.isEmpty()) {
|
if (detailCount <= 0) {
|
||||||
|
// 若明细写入异常,主动抛异常回滚事务
|
||||||
throw new IllegalStateException("发药明细写入失败,无法生成汇总单");
|
throw new IllegalStateException("发药明细写入失败,无法生成汇总单");
|
||||||
}
|
}
|
||||||
|
|
||||||
// 3. 基于已写入的明细聚合生成汇总单
|
// 3. 基于已写入的明细聚合生成发药汇总单
|
||||||
Map<String, Object> summary = dispensingSummaryMapper.calculateSummaryFromDetails(orderId);
|
// 汇总单的业务字段(如总数量、总金额)全部由数据库聚合计算,避免业务层自行计算导致时序不一致
|
||||||
if (summary == null || summary.isEmpty()) {
|
dispensingSummaryMapper.insertSummaryByOrderId(orderId);
|
||||||
throw new IllegalStateException("汇总单计算失败");
|
|
||||||
}
|
|
||||||
|
|
||||||
// 4. 写入汇总单
|
|
||||||
dispensingSummaryMapper.insertSummary(summary);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user