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("发药参数缺失或明细为空");
|
||||
}
|
||||
|
||||
// 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);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user