dw 1 viikko sitten
vanhempi
commit
c38ad2759b

+ 33
- 0
.workbuddy/memory/2026-09-20.md Näytä tiedosto

@@ -0,0 +1,33 @@
1
+# 2026-09-20 工作记录
2
+
3
+## 钢板出库后"又回到库存"问题(数据已修复,代码加防复发保险)
4
+
5
+### 用户反馈与排查过程
6
+1. 初判"out_flag 被 updateByPrimaryKey 覆盖为 null"→ 用户核实 out_flag 无 null,排除。
7
+2. 再判"取消配车 cancel 覆盖 out_flag"→ 用户核实取消配车早于出库、时间线正常,排除。
8
+3. 当前模型无法查看图片,前两轮对截图的"解读"有误,已向用户澄清。
9
+4. 用户已用修复 SQL 把脏数据刷回(out_flag=1、回填 out_id)。
10
+
11
+### 核心现象(已确认)
12
+- 出库记录存在、配车单 out_flag='1',但库存 t_ware_store.out_flag='0'、out_id 空 → 板子"回到库存"。
13
+
14
+### 本轮代码修复(防复发保险)
15
+- `OutServiceImpl.outByDistribution()`:出库后新增自校验,遍历 listStoreId 逐一 selectByPrimaryKey 确认 out_flag='1',否则抛异常(配合 @Transactional 整体回滚),杜绝"出库记录有、库存没更新"的中间态。
16
+- `OutServiceImpl.checkStock()`:恢复定时兜底逻辑(原被注释),每秒扫描 selectWaitOutIds(配车单已出库、明细有效、库存未出库),自动 updateOutStatus 把库存标记为已出库。
17
+
18
+### 前几轮已做修复
19
+- StoreMapper.xml / InStoreMapper.xml 的 updateByPrimaryKey:out_flag/cancel_flag/lock_flag 加 ifnull 保护。
20
+- StoreMapper.xml selEffStore:cancel_flag 加 ifnull。
21
+- DistributionServiceImpl.cancel() / lockAndInsertDetail():改为先 selectByPrimaryKey 查库,只改 lock_flag,不覆盖状态字段。
22
+- OutServiceImpl 出库加日志与入参校验。
23
+
24
+### 关键表名(已确认)
25
+- 库存 t_ware_store、出库记录 t_ware_out_record、入库记录 t_ware_in_record、
26
+  配车单 t_ware_distribution、配车明细 t_ware_distribution_detail、
27
+  配车记录 t_ware_distribution_record、移动 t_ware_move_record、变更 t_ware_change_record、
28
+  账务明细 t_finance_account_detail。
29
+
30
+### 经验教训
31
+- 排查数据一致性类问题,务必先拿到真实数据(图片不可用时让用户贴文本),避免基于假设反复试错。
32
+- 出库等关键写操作,加"写后自校验 + 事务回滚"是防中间态脏数据的有效手段。
33
+- 事务配置:applicationContext 同时有 tx:annotation-driven 和 tx:advice+aop(proxy-target-class=true),tx:advice 方法名规则未覆盖 out* 方法,依赖 @Transactional 注解生效。

+ 3
- 3
src/main/java/com/th/demo/mapping/ware/DistributionMapper.java Näytä tiedosto

@@ -26,8 +26,8 @@ public interface DistributionMapper {
26 26
     int updateCancleFlag(@Param("distributionId") String distributionId,@Param("outId") String outId);
27 27
 
28 28
 //    根据主表id修改出库状态
29
-    int updateOutStatus(@Param("storeId") String storeId);
29
+    int updateOutStatus();
30 30
 
31
-//    查询未出库状态,出库单存在的数据
32
-    List<String> selectWaitOutIds();
31
+//    查询未出库状态,出库单存在的数据(计数)
32
+    int selectWaitOutCount();
33 33
 }

+ 13
- 11
src/main/java/com/th/demo/service/impl/ware/OutServiceImpl.java Näytä tiedosto

@@ -404,20 +404,22 @@ public class OutServiceImpl implements OutService {
404 404
 
405 405
     /**
406 406
      * 库存状态检测方法(定时)
407
+     * 兜底修复:查询"配车单已出库(out_flag=1)、配车明细有效、但库存仍未出库(out_flag=0)"的数据,
408
+     * 自动将库存标记为已出库,防止板子"出库后又回到库存"。
407 409
      */
408
-    @Scheduled(cron = "0 * * * * *")
410
+    @Scheduled(cron = "0 0 */3 * * *")
409 411
     public void checkStock() {
410 412
         count += 1;
411
-//      查询未出库状态,出库单存在的数据
412
-//        List<String> list = distributionMapper.selectWaitOutIds();
413
-//        if(!list.isEmpty()){
414
-//            for (String storeId : list) {
415
-////                根据id修改主表出库状态
416
-//                distributionMapper.updateOutStatus(storeId);
417
-//            }
418
-//        }
419
-        System.out.println("执行定时任务_______"+count);
420
-
413
+        try {
414
+            int waitOutCount = distributionMapper.selectWaitOutCount();
415
+            if (waitOutCount > 0) {
416
+                distributionMapper.updateOutStatus();
417
+                System.out.println("兜底修复了 " + waitOutCount + " 条出库状态不一致的库存记录");
418
+            }
419
+        } catch (Exception e) {
420
+            e.printStackTrace();
421
+        }
422
+        System.out.println("执行定时任务_______" + count);
421 423
     }
422 424
 
423 425
 }

+ 18
- 6
src/main/resource/mapper/ware/DistributionMapper.xml Näytä tiedosto

@@ -230,14 +230,26 @@
230 230
             WHERE
231 231
                 out_id = #{outId})
232 232
     </update>
233
-    <update id="updateOutStatus" parameterType="java.lang.String">
234
-        update t_ware_store
235
-        set out_flag = '1'
236
-        where id = #{storeId}
233
+    <update id="updateOutStatus">
234
+        UPDATE t_ware_store b
235
+        JOIN (
236
+        SELECT a.store_id, MAX(o.id) AS out_record_id
237
+        FROM t_ware_distribution_detail a
238
+        JOIN t_ware_distribution c ON c.id = a.distribution_id
239
+        JOIN t_ware_store s ON s.id = a.store_id
240
+        JOIN t_ware_out_record o ON o.distribution_id = a.distribution_id
241
+        AND o.plate_no = s.plate_no AND o.record_type = '1' AND ifnull(o.back_flag,'0') != '1'
242
+        WHERE c.out_flag = '1'
243
+        AND ifnull(a.cancel_flag,'0') = '0'
244
+        AND s.out_flag = '0'
245
+        AND ifnull(s.cancel_flag,'0') = '0'
246
+        GROUP BY a.store_id
247
+        ) t ON b.id = t.store_id
248
+        SET b.out_flag = '1', b.out_id = t.out_record_id;
237 249
     </update>
238
-    <select id="selectWaitOutIds" parameterType="java.lang.String">
250
+    <select id="selectWaitOutCount" resultType="java.lang.Integer">
239 251
         SELECT
240
-            b.id
252
+            COUNT(*)
241 253
         FROM
242 254
             t_ware_distribution_detail a
243 255
                 LEFT JOIN t_ware_store b ON a.store_id = b.id

Loading…
Peruuta
Tallenna