feat(inspect): 优化巡检工单生成机制并增强并发安全控制

- 新增数据库当前时间获取方法,避免应用与数据库时钟差异
- 修复计划ID匹配逻辑,将模糊查询改为精确匹配
- 添加数据库表前缀别名,确保排序字段准确性
- 引入分布式锁机制,通过FOR UPDATE串行化并发任务
- 实现应用层幂等检查,避免重复生成工单
- 优化SQL查询性能,移除可能导致索引失效的TRUNC函数
- 添加Oracle唯一约束异常处理,提升系统容错能力
- 完善计划时间推进逻辑,基于计划当前时间准确计算下次执行时间
- 分离事务边界,确保工单生成与计划更新的独立性
- 重构序列名称,统一命名规范
- 优化分页查询语法,适配Oracle数据库特性
master
zangch@mesnac.com 6 days ago
parent 5811a7c580
commit 8cd51654b7

@ -73,16 +73,33 @@ CREATE SEQUENCE "HAIWEI"."SEQ_DMS_INSPECT_RTE_DTL"
CACHE 20;
-- ----------------------------
-- 4A. SEQ_DMS_INSPECT_INSTANCE_DETAIL (巡检工单明细)
-- 4A. SEQ_DMS_INSP_INST_DETAIL (巡检工单明细)
-- 表: DMS_INSPECT_INSTANCE_DETAIL
-- ----------------------------
BEGIN
EXECUTE IMMEDIATE 'DROP SEQUENCE "HAIWEI"."SEQ_DMS_INSPECT_INSTANCE_DETAIL"';
EXECUTE IMMEDIATE 'DROP SEQUENCE "HAIWEI"."SEQ_DMS_INSP_INST_DETAIL"';
EXCEPTION
WHEN OTHERS THEN NULL;
END;
/
CREATE SEQUENCE "HAIWEI"."SEQ_DMS_INSPECT_INSTANCE_DETAIL"
CREATE SEQUENCE "HAIWEI"."SEQ_DMS_INSP_INST_DETAIL"
MINVALUE 1
MAXVALUE 9999999999999999999999999999
START WITH 1
INCREMENT BY 1
CACHE 20;
-- ----------------------------
-- 4B. SEQ_DMS_INSP_DET_PROJ (巡检明细项目)
-- 表: DMS_INSPECT_INST_DET_PROJ
-- ----------------------------
BEGIN
EXECUTE IMMEDIATE 'DROP SEQUENCE "HAIWEI"."SEQ_DMS_INSP_DET_PROJ"';
EXCEPTION
WHEN OTHERS THEN NULL;
END;
/
CREATE SEQUENCE "HAIWEI"."SEQ_DMS_INSP_DET_PROJ"
MINVALUE 1
MAXVALUE 9999999999999999999999999999
START WITH 1
@ -242,7 +259,6 @@ CREATE SEQUENCE "HAIWEI"."SEQ_FAULT_INSTANCE_ACTIVITY"
INCREMENT BY 1
CACHE 20;
-- ----------------------------
-- ----------------------------
-- 14. SEQ_DMS_BILLS_INSPECT_INSTANCE (巡检工单)
-- 表: DMS_BILLS_INSPECT_INSTANCE
@ -276,6 +292,7 @@ CREATE SEQUENCE "HAIWEI"."SEQ_DMS_BILLS_INSPECT_ACTIVITY"
START WITH 1
INCREMENT BY 1
CACHE 20;
-- 14. SEQ_DMS_MAINT_INST (保养工单)
-- 表: DMS_BILLS_MAINT_INSTANCE
-- ----------------------------
@ -530,6 +547,23 @@ CREATE SEQUENCE "HAIWEI"."SEQ_DMS_REC_SHUT_DOWN"
INCREMENT BY 1
CACHE 20;
-- ----------------------------
-- 29. SEQ_MES_BASE_ATTACH_INFO (附件信息)
-- 表: DMS_BASE_ATTACH_INFO
-- ----------------------------
BEGIN
EXECUTE IMMEDIATE 'DROP SEQUENCE "HAIWEI"."SEQ_MES_BASE_ATTACH_INFO"';
EXCEPTION
WHEN OTHERS THEN NULL;
END;
/
CREATE SEQUENCE "HAIWEI"."SEQ_MES_BASE_ATTACH_INFO"
MINVALUE 1
MAXVALUE 9999999999999999999999999999
START WITH 1
INCREMENT BY 1
CACHE 20;
-- ============================================
-- 序列对齐:按 MAX(主键列)+1 设置 NEXTVALOracle 11g 兼容方案)
-- ============================================
@ -591,7 +625,9 @@ BEGIN
-- 4. 点检路线明细
sync_seq('HAIWEI.SEQ_DMS_INSPECT_RTE_DTL', 'HAIWEI.DMS_INSPECT_ROUTE_DETAIL', 'ROUTE_DETAIL_ID');
-- 4A. 巡检工单明细
sync_seq('HAIWEI.SEQ_DMS_INSPECT_INSTANCE_DETAIL','HAIWEI.DMS_INSPECT_INSTANCE_DETAIL', 'INSTANCE_DETAIL_ID');
sync_seq('HAIWEI.SEQ_DMS_INSP_INST_DETAIL', 'HAIWEI.DMS_INSPECT_INSTANCE_DETAIL', 'INSTANCE_DETAIL_ID');
-- 4B. 巡检明细项目
sync_seq('HAIWEI.SEQ_DMS_INSP_DET_PROJ', 'HAIWEI.DMS_INSPECT_INST_DET_PROJ', 'INSTANCE_DETAIL_PROJECT_ID');
-- 5. 润滑标准
sync_seq('HAIWEI.SEQ_DMS_LUBE_STD', 'HAIWEI.DMS_BASE_LUBE_STANDARD', 'LUBE_STANDARD_ID');
-- 6. 润滑部位
@ -644,13 +680,16 @@ BEGIN
sync_seq('HAIWEI.SEQ_DMS_REPAIR_WORK_ORDER', 'HAIWEI.DMS_REPAIR_WORK_ORDER', 'WORK_ORDER_ID');
-- 28. 停机记录
sync_seq('HAIWEI.SEQ_DMS_REC_SHUT_DOWN', 'HAIWEI.DMS_RECORD_SHUT_DOWN', 'RECORD_SHUT_DOWN_ID');
-- 29. 附件信息
sync_seq('HAIWEI.SEQ_MES_BASE_ATTACH_INFO', 'HAIWEI.DMS_BASE_ATTACH_INFO', 'ATTACH_ID');
-- 为所有序列授权 + 创建公共同义词(保证跨 schema 应用可用)
grant_and_synonym('SEQ_DMS_INSPECT_PROJ');
grant_and_synonym('SEQ_DMS_INSPECT_ROUTE');
grant_and_synonym('SEQ_DMS_INSPECT_STD');
grant_and_synonym('SEQ_DMS_INSPECT_RTE_DTL');
grant_and_synonym('SEQ_DMS_INSPECT_INSTANCE_DETAIL');
grant_and_synonym('SEQ_DMS_INSP_INST_DETAIL');
grant_and_synonym('SEQ_DMS_INSP_DET_PROJ');
grant_and_synonym('SEQ_DMS_LUBE_STD');
grant_and_synonym('SEQ_DMS_LUBE_STATION');
grant_and_synonym('SEQ_DMS_MAINT_PROJ');
@ -677,12 +716,13 @@ BEGIN
grant_and_synonym('SEQ_DMS_REPAIR_RECORD');
grant_and_synonym('SEQ_DMS_REPAIR_WORK_ORDER');
grant_and_synonym('SEQ_DMS_REC_SHUT_DOWN');
grant_and_synonym('SEQ_MES_BASE_ATTACH_INFO');
END;
/
-- ============================================
-- 执行完成提示
-- ============================================
-- 共创建 28 个序列,已按 MAX(主键)+1 对齐,已授权+同义词
-- 共创建 33 个序列,已按 MAX(主键)+1 对齐,已授权+同义词
-- 验证:
-- SELECT SEQUENCE_NAME, LAST_NUMBER FROM ALL_SEQUENCES WHERE SEQUENCE_OWNER='HAIWEI' AND (SEQUENCE_NAME LIKE 'SEQ_DMS%' OR SEQUENCE_NAME LIKE 'SEQ_FAULT%');

@ -4,6 +4,7 @@ import com.aucma.dms.domain.DmsBillsInspectInstance;
import com.aucma.dms.domain.DmsRecordInspect;
import org.apache.ibatis.annotations.Param;
import java.util.Date;
import java.util.List;
/**
@ -91,4 +92,9 @@ public interface DmsBillsInspectInstanceMapper
* @return
*/
int countByPlanIdAndToday(@Param("planInspectId") Long planInspectId);
/**
* SYSDATE
*/
Date selectDbNow();
}

@ -80,4 +80,12 @@ public interface DmsPlanInspectMapper
int updatePlanNextTime(@Param("planInspectId") Long planInspectId,
@Param("planTime") Date planTime);
/**
* FOR UPDATE
*
* @param planInspectId ID
* @return IDnull
*/
Long lockPlanById(@Param("planInspectId") Long planInspectId);
}

@ -13,6 +13,8 @@ import com.aucma.dms.service.IDmsBillsInspectInstanceService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DataIntegrityViolationException;
import org.springframework.dao.DuplicateKeyException;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
@ -36,6 +38,8 @@ public class DmsBillsInspectInstanceServiceImpl implements IDmsBillsInspectInsta
@Autowired
private DmsBillsInspectInstanceMapper dmsBillsInspectInstanceMapper;
@Autowired
private DmsPlanInspectMapper dmsPlanInspectMapper;
@Autowired
private DmsBillsInspectInstanceActivityMapper dmsBillsInspectInstanceActivityMapper;
@Autowired
private DmsRepairInstanceMapper dmsRepairInstanceMapper;
@ -105,7 +109,23 @@ public class DmsBillsInspectInstanceServiceImpl implements IDmsBillsInspectInsta
dmsBillsInspectInstance.setIsFlag("1");
dmsBillsInspectInstance.setInspectStatus(DmsConstants.DMS_BILLS_INSPECT_INSTANCE_INSPECT_STATUS_TO_INSPECT);
dmsBillsInspectInstance.setCreateBy(SecurityUtils.getLoginUser()==null ? SecurityUtils.getUserId() :SecurityUtils.getLoginUser().getUser().getUserId());
int i = dmsBillsInspectInstanceMapper.insertDmsBillsInspectInstance(dmsBillsInspectInstance);
int i;
try {
// 4) 插入主工单:
// 若并发场景下命中唯一约束,则视为“已生成”,返回 0。
i = dmsBillsInspectInstanceMapper.insertDmsBillsInspectInstance(dmsBillsInspectInstance);
} catch (DuplicateKeyException e) {
log.debug("巡检工单触发唯一约束(重复生成),跳过 | planInspectId={}, billsInspectCode={}",
dmsBillsInspectInstance.getPlanInspectId(), dmsBillsInspectInstance.getBillsInspectCode());
return 0;
} catch (DataIntegrityViolationException e) {
if (isOracleUniqueViolation(e)) {
log.debug("巡检工单触发 ORA-00001(重复生成),跳过 | planInspectId={}, billsInspectCode={}",
dmsBillsInspectInstance.getPlanInspectId(), dmsBillsInspectInstance.getBillsInspectCode());
return 0;
}
throw e;
}
log.info("新增巡检工单 | inspectInstanceId={}, billsInspectCode={}, inspectRouteId={}, inspectType={}",
dmsBillsInspectInstance.getInspectInstanceId(), dmsBillsInspectInstance.getBillsInspectCode(),
dmsBillsInspectInstance.getInspectRouteId(), dmsBillsInspectInstance.getInspectType());
@ -153,6 +173,20 @@ public class DmsBillsInspectInstanceServiceImpl implements IDmsBillsInspectInsta
return i;
}
private boolean isOracleUniqueViolation(Throwable e) {
Throwable cursor = e;
while (cursor != null) {
String msg = cursor.getMessage();
// ORA-00001 = unique constraint violated
// 逐层检查 cause兼容不同异常包装层Spring/MyBatis/JDBC
if (msg != null && msg.contains("ORA-00001")) {
return true;
}
cursor = cursor.getCause();
}
return false;
}
/**
*
*
@ -405,7 +439,30 @@ public class DmsBillsInspectInstanceServiceImpl implements IDmsBillsInspectInsta
// @Transactional(rollbackFor = Exception.class)
@Transactional(propagation = Propagation.REQUIRES_NEW, rollbackFor = Exception.class)
public int insertCompletedInspectInstance(DmsBillsInspectInstance dmsBillsInspectInstance) {
Date now = new Date();
Long planInspectId = dmsBillsInspectInstance.getPlanInspectId();
if (planInspectId != null) {
// 1) 先锁计划行FOR UPDATE
// 将同一计划的并发任务串行化,避免同时进入插入阶段。
Long lockedId = dmsPlanInspectMapper.lockPlanById(planInspectId);
if (lockedId == null) {
log.warn("巡检计划不存在,跳过工单生成 | planInspectId={}", planInspectId);
return 0;
}
// 2) 再做当天查重(应用层幂等):
// 这里返回已生成则直接跳过。
int existCount = dmsBillsInspectInstanceMapper.countByPlanIdAndToday(planInspectId);
if (existCount > 0) {
log.debug("巡检计划今天已生成工单,跳过 | planInspectId={}", planInspectId);
return 0;
}
}
// 3) 统一使用 DB 时间作为“当天”基准,减少应用机/DB 机时钟偏差带来的跨天误判。
Date now = dmsBillsInspectInstanceMapper.selectDbNow();
if (now == null) {
// 理论兜底DB 时间查询异常时退回应用时间,避免任务中断。
now = new Date();
}
log.info("开始创建已完成巡检工单 | billsInspectCode={}, planInspectId={}, inspectRouteId={}, inspectType={}",
dmsBillsInspectInstance.getBillsInspectCode(), dmsBillsInspectInstance.getPlanInspectId(),
dmsBillsInspectInstance.getInspectRouteId(), dmsBillsInspectInstance.getInspectType());
@ -422,9 +479,23 @@ public class DmsBillsInspectInstanceServiceImpl implements IDmsBillsInspectInsta
dmsBillsInspectInstance.setCreateBy(-1L);
}
int i = dmsBillsInspectInstanceMapper.insertDmsBillsInspectInstance(dmsBillsInspectInstance);
int i;
try {
i = dmsBillsInspectInstanceMapper.insertDmsBillsInspectInstance(dmsBillsInspectInstance);
} catch (DuplicateKeyException e) {
log.debug("巡检工单触发唯一约束(重复生成),跳过 | planInspectId={}, billsInspectCode={}",
dmsBillsInspectInstance.getPlanInspectId(), dmsBillsInspectInstance.getBillsInspectCode());
return 0;
} catch (DataIntegrityViolationException e) {
if (isOracleUniqueViolation(e)) {
log.debug("巡检工单触发 ORA-00001(重复生成),跳过 | planInspectId={}, billsInspectCode={}",
dmsBillsInspectInstance.getPlanInspectId(), dmsBillsInspectInstance.getBillsInspectCode());
return 0;
}
throw e;
}
// 2. 创建工单实例节点(第一步)
// 5) 创建工单活动节点(第一步)
DmsBillsInspectInstanceActivity activity = new DmsBillsInspectInstanceActivity();
activity.setInspectInstanceId(dmsBillsInspectInstance.getInspectInstanceId());
activity.setInspectRouteId(dmsBillsInspectInstance.getInspectRouteId());
@ -434,7 +505,7 @@ public class DmsBillsInspectInstanceServiceImpl implements IDmsBillsInspectInsta
activity.setProcessHandleStatus("3"); // 已完成
dmsBillsInspectInstanceActivityMapper.insertDmsBillsInspectInstanceActivity(activity);
// 3. 创建巡检工单明细:路线所有设备均为正常/已完成状态
// 6) 创建巡检工单明细:路线上的设备默认“已完成 + 合格”。
if (dmsBillsInspectInstance.getInspectRouteId() != null) {
DmsInspectRouteDetail queryRouteDetail = new DmsInspectRouteDetail();
queryRouteDetail.setInspectRouteId(dmsBillsInspectInstance.getInspectRouteId());
@ -456,7 +527,7 @@ public class DmsBillsInspectInstanceServiceImpl implements IDmsBillsInspectInsta
detail.setInspectStatus(DmsConstants.DMS_INSPECT_INSTANCE_DETAIL_INSPECT_STATUS_PASS); // 1=正常/合格
dmsInspectInstanceDetailMapper.insertDmsInspectInstanceDetail(detail);
// 创建明细项目记录
// 7) 创建明细项目记录:仅在“巡检标准 -> 项目”映射存在时落库。
Long projectId = dmsInspectInstanceDetailMapper.selectProjectId(routeDetail.getInspectStandard());
if (projectId != null) {
DmsInspectInstanceDetailProject detailProject = new DmsInspectInstanceDetailProject();

@ -7,18 +7,18 @@ import com.aucma.common.utils.uuid.Seq;
import com.aucma.dms.domain.DmsBillsInspectInstance;
import com.aucma.dms.domain.DmsPlanInspect;
import com.aucma.dms.mapper.DmsBaseInspectRouteMapper;
import com.aucma.dms.mapper.DmsBillsInspectInstanceMapper;
import com.aucma.dms.mapper.DmsPlanInspectMapper;
import com.aucma.dms.service.IDmsBillsInspectInstanceService;
import com.aucma.dms.service.IDmsPlanInspectService;
import com.aucma.quartz.util.CronUtils;
import org.quartz.CronExpression;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.text.ParseException;
import java.util.Date;
import java.util.List;
@ -40,11 +40,10 @@ public class DmsPlanInspectServiceImpl implements IDmsPlanInspectService
@Autowired
private DmsBaseInspectRouteMapper dmsBaseInspectRouteMapper;
@Autowired
private DmsBillsInspectInstanceMapper dmsBillsInspectInstanceMapper;
@Autowired
private IDmsBillsInspectInstanceService dmsBillsInspectInstanceService;
@Autowired
private DmsPlanInspectTxService dmsPlanInspectTxService;
/**
*
@ -271,36 +270,34 @@ public class DmsPlanInspectServiceImpl implements IDmsPlanInspectService
*
* cron
*/
@Scheduled(cron = "0 0 0 * * ?")
@Scheduled(cron = "0 0 0 * * ?") // 原生产策略:每天 0 点执行
// @Scheduled(cron = "0 * * * * ?") // 测试策略:每分钟执行一次
// @Transactional(rollbackFor = Exception.class)
public void generateDailyInspectWorkOrders() {
log.info("========== 开始执行巡检工单生成任务 ==========");
int count = 0;
int skipCount = 0;
try {
// 通过Mapper查询今天需要执行的巡检计划plan_time <= 今天)
// 先把“到期的计划”全部拉出来,后续逐条处理。
// 注意:这里不做事务包裹,避免某一条失败影响整批调度。
List<DmsPlanInspect> plans = dmsPlanInspectMapper.selectPendingInspectPlans();
for (DmsPlanInspect plan : plans) {
try {
// 先提取关键字段,便于后续日志统一打印。
Long planInspectId = plan.getPlanInspectId();
String planInspectCode = plan.getPlanInspectCode();
Long inspectRouteId = plan.getInspectRouteId();
// 计划编码为空通常属于脏数据,直接跳过,避免生成不可追踪工单。
if (planInspectCode == null || planInspectCode.isEmpty()) {
log.warn("巡检计划ID[{}]编号为空,跳过", planInspectId);
skipCount++;
continue;
}
// 通过Mapper检查今天是否已生成工单避免重复
int existCount = dmsBillsInspectInstanceMapper.countByPlanIdAndToday(planInspectId);
if (existCount > 0) {
log.debug("巡检计划[{}]今天已生成工单,跳过", planInspectCode);
continue;
}
// 构建巡检工单对象(工单中所有设备状态默认为正常,异常可在网页端维护)
// 预生成业务单号(仅用于业务展示)。
// 真正“是否允许生成”在 TxA 内部通过加锁 + 查重 + 唯一约束做最终判定。
String billsCode = Seq.getId(Seq.dmsBillsFaultInstanceSeqType, "XJ");
DmsBillsInspectInstance instance = new DmsBillsInspectInstance();
instance.setBillsInspectCode(billsCode);
@ -309,18 +306,25 @@ public class DmsPlanInspectServiceImpl implements IDmsPlanInspectService
instance.setInspectType(plan.getInspectType());
instance.setDeviceAmount(plan.getDeviceAmount());
instance.setPerformer(plan.getPerformer());
// 创建人优先使用计划的创建人,若无则使用-1L表示系统自动创建
// 创建人优先继承计划创建人;兜底 -1 表示系统自动生成。
instance.setCreateBy(plan.getCreateBy() != null ? plan.getCreateBy() : -1L);
// 通过Service创建已完成状态的巡检工单含明细路线所有设备正常
dmsBillsInspectInstanceService.insertCompletedInspectInstance(instance);
// TxA生成工单REQUIRES_NEW
// 返回 0 代表被并发任务抢先生成或命中唯一约束,视为“正常跳过”。
int insertRows = dmsBillsInspectInstanceService.insertCompletedInspectInstance(instance);
if (insertRows > 0) {
count++;
log.info("已为巡检计划[{}]生成已完成工单[{}]", planInspectCode, billsCode);
// 更新计划的下次执行时间根据cron表达式或默认+1天
// TxB推进下次执行时间单独新事务
// 即便 TxB 失败,也不回滚已成功提交的工单(避免“误回滚”)。
updateInspectPlanNextTime(plan);
} else {
skipCount++;
log.debug("巡检计划[{}]已被其他任务生成或不满足生成条件,跳过", planInspectCode);
}
} catch (Exception e) {
// 单条计划异常只记录,不中断整批调度任务。
log.error("为巡检计划生成工单失败 | planInspectId={}, planInspectCode={}, cronExpression={}, planTime={}, inspectType={}, inspectRouteId={}, 异常信息: {}",
plan.getPlanInspectId(), plan.getPlanInspectCode(), plan.getCronExpression(),
plan.getPlanTime(), plan.getInspectType(), plan.getInspectRouteId(),
@ -342,14 +346,17 @@ public class DmsPlanInspectServiceImpl implements IDmsPlanInspectService
Date nextTime = null;
String cronExpression = plan.getCronExpression();
if (cronExpression != null && !cronExpression.isEmpty()) {
nextTime = CronUtils.getNextExecution(cronExpression);
// 基于“计划当前时间”推进,而不是基于“当前系统时间”直接算一次,
// 可以避免周/月计划在某些场景下被推进到错误时间点。
nextTime = calculateNextPlanTime(cronExpression, plan.getPlanTime());
}
if (nextTime == null) {
log.warn("巡检计划下次执行时间计算为null, 使用默认+1天 | planInspectId={}, planInspectCode={}, cronExpression={}",
plan.getPlanInspectId(), plan.getPlanInspectCode(), cronExpression);
nextTime = new Date(System.currentTimeMillis() + 24 * 60 * 60 * 1000L);
}
dmsPlanInspectMapper.updatePlanNextTime(plan.getPlanInspectId(), nextTime);
// 使用独立事务推进计划时间,避免影响已成功提交的工单数据。
dmsPlanInspectTxService.updatePlanNextTimeInNewTx(plan.getPlanInspectId(), nextTime);
log.debug("更新巡检计划下次执行时间 | planInspectCode={}, nextTime={}", plan.getPlanInspectCode(), nextTime);
} catch (Exception e) {
log.error("更新巡检计划下次执行时间失败 | planInspectId={}, planInspectCode={}, cronExpression={}, 异常信息: {}",
@ -357,4 +364,25 @@ public class DmsPlanInspectServiceImpl implements IDmsPlanInspectService
e.getMessage(), e);
}
}
/**
* :
* 1) planTime
* 2)
*/
private Date calculateNextPlanTime(String cronExpression, Date currentPlanTime) {
try {
CronExpression cron = new CronExpression(cronExpression);
Date now = new Date();
Date cursor = currentPlanTime != null ? currentPlanTime : now;
Date next = cron.getNextValidTimeAfter(cursor);
while (next != null && !next.after(now)) {
next = cron.getNextValidTimeAfter(next);
}
return next;
} catch (ParseException e) {
log.error("cron表达式非法无法计算下次执行时间 | cronExpression={}, 异常信息: {}", cronExpression, e.getMessage(), e);
return null;
}
}
}

@ -54,7 +54,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<select id="selectDmsBillsInspectInstanceList" parameterType="DmsBillsInspectInstance" resultMap="DmsBillsInspectInstanceResult">
<include refid="selectDmsBillsInspectInstanceVo"/>
<where>
<if test="planInspectId != null "> and a.plan_inspect_id like concat('%',#{planInspectId},'%') </if>
<if test="planInspectId != null "> and a.plan_inspect_id = #{planInspectId}</if>
<if test="inspectInstanceId != null "> and a.inspect_instance_id = #{inspectInstanceId}</if>
<!-- 已废弃审批流 -->
<!-- <if test="wfProcessId != null "> and a.wf_process_id = #{wfProcessId}</if> -->
@ -67,7 +67,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<if test="inspectStatus != null and inspectStatus != ''"> and a.inspect_status = #{inspectStatus}</if>
<if test="isFlag != null and isFlag != ''"> and a.is_flag = #{isFlag}</if>
</where>
order by create_time desc
order by a.create_time desc
</select>
<select id="selectPoint" parameterType="DmsBillsInspectInstance" resultMap="DmsBillsInspectInstanceResult">
<include refid="selectDmsBillsInspectInstanceVo"/>
@ -194,6 +194,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
delete from dms_bills_inspect_instance where inspect_instance_id = #{inspectInstanceId}
</delete>
<delete id="deleteDmsBillsInspectInstanceByInspectInstanceIds" parameterType="String">
delete from dms_bills_inspect_instance where inspect_instance_id in
<foreach item="inspectInstanceId" collection="array" open="(" separator="," close=")">
@ -202,20 +203,11 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
</delete>
<select id="selectNewestDmsBillsInspectInstance" parameterType="DmsBillsInspectInstance" resultMap="DmsBillsInspectInstanceResult">
SELECT * FROM (
select
dbii.inspect_instance_id,
dbii.plan_inspect_id,
dbii.wf_process_id,
dbii.inspect_type,
dbii.bills_inspect_code,
dbii.plan_begin_time,
@ -237,10 +229,11 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<if test="inspectType != null and inspectType != ''"> and dbii.inspect_type = #{inspectType}</if>
<if test="billsInspectCode != null and billsInspectCode != ''"> and dbii.bills_inspect_code = #{billsInspectCode}</if>
<if test="inspectStatus != null and inspectStatus != ''"> and dbii.inspect_status = #{inspectStatus}</if>
<if test="inspectStatusStr != null and inspectStatusStr != ''"> and dbii.inspect_status in (${inspectStatusStr})</if>
<if test="inspectStatusStr != null and inspectStatusStr != ''"> and instr(',' || #{inspectStatusStr} || ',', ',' || dbii.inspect_status || ',') &gt; 0</if>
<if test="isFlag != null and isFlag != ''"> and dbii.is_flag = #{isFlag}</if>
</where>
order by dbii.create_time desc limit 1
order by dbii.create_time desc
) where rownum = 1
</select>
<select id="selectRecord" resultType="com.aucma.dms.domain.DmsRecordInspect" parameterType="java.lang.Long">
select
@ -294,7 +287,14 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
SELECT COUNT(1)
FROM dms_bills_inspect_instance
WHERE plan_inspect_id = #{planInspectId}
AND TRUNC(create_time) = TRUNC(SYSDATE)
-- 使用 [当天00:00, 次日00:00) 范围,避免 TRUNC(create_time) 带来的索引失效风险
AND create_time &gt;= TRUNC(SYSDATE)
AND create_time &lt; TRUNC(SYSDATE) + 1
</select>
<!-- 统一从 DB 读取当前时间,避免应用与数据库时钟差异 -->
<select id="selectDbNow" resultType="java.util.Date">
SELECT SYSDATE FROM DUAL
</select>
</mapper>

@ -47,7 +47,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<insert id="insertDmsInspectInstanceDetail" parameterType="DmsInspectInstanceDetail">
<selectKey keyProperty="instanceDetailId" resultType="long" order="BEFORE">
SELECT HAIWEI.SEQ_DMS_INSPECT_INSTANCE_DETAIL.NEXTVAL FROM DUAL
SELECT HAIWEI.SEQ_DMS_INSP_INST_DETAIL.NEXTVAL FROM DUAL
</selectKey>
insert into dms_inspect_instance_detail
<trim prefix="(" suffix=")" suffixOverrides=",">
@ -113,11 +113,6 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
</delete>
<sql id="selectDmsInspectInstanceDetailJoinVo">
select
diid.instance_detail_id,
@ -153,9 +148,10 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
</select>
<select id="selectDmsInspectInstanceDetailByUI" resultMap="DmsInspectInstanceDetailResult">
SELECT * FROM (
<include refid="selectDmsInspectInstanceDetailJoinVo"/>
where diid.inspect_instance_id = #{inspectInstanceId} and dbdl.device_code = #{deviceCode}
limit 1
) where rownum = 1
</select>
<select id="selectProjectId" resultType="java.lang.Long" parameterType="java.lang.String">
SELECT x.inspect_project_id FROM dms_base_inspect_standard x where x.inspect_standard_id = #{inspectStandard}

@ -48,9 +48,13 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
where instance_detail_project_id = #{instanceDetailProjectId}
</select>
<insert id="insertDmsInspectInstanceDetailProject" parameterType="DmsInspectInstanceDetailProject" useGeneratedKeys="true" keyProperty="instanceDetailProjectId">
<insert id="insertDmsInspectInstanceDetailProject" parameterType="DmsInspectInstanceDetailProject">
<selectKey keyProperty="instanceDetailProjectId" resultType="long" order="BEFORE">
SELECT HAIWEI.SEQ_DMS_INSP_DET_PROJ.NEXTVAL FROM DUAL
</selectKey>
insert into dms_inspect_inst_det_proj
<trim prefix="(" suffix=")" suffixOverrides=",">
instance_detail_project_id,
<if test="instanceDetailId != null">instance_detail_id,</if>
<if test="inspectProjectId != null">inspect_project_id,</if>
<if test="inspectProjectStatus != null">inspect_project_status,</if>
@ -68,6 +72,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<if test="updateTime != null">update_time,</if>
</trim>
<trim prefix="values (" suffix=")" suffixOverrides=",">
#{instanceDetailProjectId},
<if test="instanceDetailId != null">#{instanceDetailId},</if>
<if test="inspectProjectId != null">#{inspectProjectId},</if>
<if test="inspectProjectStatus != null">#{inspectProjectStatus},</if>

@ -169,4 +169,13 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
SET plan_time = #{planTime}, update_time = SYSDATE
WHERE plan_inspect_id = #{planInspectId}
</update>
<!-- 锁定计划行,避免并发重复生成工单 -->
<select id="lockPlanById" resultType="java.lang.Long">
<!-- FOR UPDATE: 对同一 plan_inspect_id 的并发任务形成串行执行 -->
SELECT plan_inspect_id
FROM dms_plan_inspect
WHERE plan_inspect_id = #{planInspectId}
FOR UPDATE
</select>
</mapper>

Loading…
Cancel
Save