| | |
| | | patMedInhosp.setHospitaldistrictname(dto.getAreaName()); |
| | | } |
| | | |
| | | /** |
| | | * 处理患者档案(新增或更新) |
| | | * 使用 Redis 分布式锁防止并发重复插入 |
| | | */ |
| | | private PatArchive processPatientArchive(ServiceSLTDInhospResDTO dto) { |
| | | // 构建锁的 key:基于 patientno 或 idcardno |
| | | String lockKey = "pat_archive_lock:" + |
| | | (StringUtils.isNotEmpty(dto.getMedicalRecordNo()) ? dto.getMedicalRecordNo() : dto.getIdCardNo()); |
| | | |
| | | // 尝试获取分布式锁,最多等待 3 秒,锁定 10 秒自动释放 |
| | | Boolean lockAcquired = redisTemplate.opsForValue().setIfAbsent(lockKey, "1", 10, TimeUnit.SECONDS); |
| | | |
| | | if (lockAcquired == null || !lockAcquired) { |
| | | log.warn("【processPatientArchive】获取分布式锁失败,跳过本次处理(其他线程正在处理),patientno={}", dto.getMedicalRecordNo()); |
| | | // 等待一段时间后重试查询 |
| | | try { |
| | | Thread.sleep(500); |
| | | } catch (InterruptedException e) { |
| | | Thread.currentThread().interrupt(); |
| | | } |
| | | } |
| | | |
| | | try { |
| | | return doProcessPatientArchive(dto); |
| | | } finally { |
| | | // 释放锁 |
| | | if (lockAcquired != null && lockAcquired) { |
| | | redisTemplate.delete(lockKey); |
| | | } |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * 实际执行患者档案处理逻辑 |
| | | */ |
| | | private PatArchive doProcessPatientArchive(ServiceSLTDInhospResDTO dto) { |
| | | List<PatArchive> existingArchives = null; |
| | | log.info("【processPatientArchive】新增患者档案,查询入参信息patientno:{},idcardno:{}", dto.getMedicalRecordNo(), dto.getIdCardNo()); |
| | | // 第一步:按 patientno 精确查重(与插入时使用的 medicalRecordNo 一致) |
| | |
| | | PatArchive queryByPatientNo = new PatArchive(); |
| | | queryByPatientNo.setPatientno(patientno); |
| | | existingArchives = patArchiveService.selectPatArchiveList(queryByPatientNo); |
| | | log.debug("【processPatientArchive】按patientno查询,patientno={}, 结果数量={}", patientno, existingArchives.size()); |
| | | } |
| | | |
| | | // 第二步:按 patientno 查不到时,按 idcardno 查重(分步OR,避免AND条件漏查) |
| | |
| | | PatArchive queryByIdCard = new PatArchive(); |
| | | queryByIdCard.setIdcardno(dto.getIdCardNo().trim()); |
| | | existingArchives = patArchiveService.selectPatArchiveList(queryByIdCard); |
| | | log.debug("【processPatientArchive】按idcardno查询,idcardno={}, 结果数量={}", dto.getIdCardNo(), existingArchives.size()); |
| | | } |
| | | |
| | | PatArchive patArchive = buildPatientArchive(dto); |
| | | |
| | | log.info("【processPatientArchive】患者档案查重完成,patientno={}, 是否已存在={}", |
| | | patArchive.getPatientno(), CollectionUtils.isEmpty(existingArchives) ? "否" : "是(id=" + existingArchives.get(0).getId() + ")"); |
| | | |
| | | if (CollectionUtils.isEmpty(existingArchives)) { |
| | | try { |
| | | //再查一次,确保不会有重复的 |
| | | PatArchive queryByIdCard = new PatArchive(); |
| | | if(StringUtils.isNotEmpty(dto.getIdCardNo())) queryByIdCard.setIdcardno(dto.getIdCardNo().trim()); |
| | | if(StringUtils.isNotEmpty(dto.getMedicalRecordNo())) queryByIdCard.setPatientno(dto.getMedicalRecordNo()); |
| | | List<PatArchive> archivesByIdCard = patArchiveService.selectPatArchiveList(queryByIdCard); |
| | | |
| | | if (CollectionUtils.isEmpty(archivesByIdCard)) patArchiveService.insertPatArchive(patArchive); |
| | | log.info("【processPatientArchive】新增患者档案,患者编号:{}", patArchive.getPatientno()); |
| | | // 最终确认查询(防御性编程:防止Redis锁失效等极端情况) |
| | | PatArchive finalQuery = new PatArchive(); |
| | | if (StringUtils.isNotEmpty(dto.getIdCardNo())) { |
| | | finalQuery.setIdcardno(dto.getIdCardNo().trim()); |
| | | } |
| | | if (StringUtils.isNotEmpty(dto.getMedicalRecordNo())) { |
| | | finalQuery.setPatientno(dto.getMedicalRecordNo()); |
| | | } |
| | | |
| | | List<PatArchive> finalCheck = patArchiveService.selectPatArchiveList(finalQuery); |
| | | log.info("【processPatientArchive】最终确认查询,patientno={}, idcardno={}, 结果数量={}", |
| | | dto.getMedicalRecordNo(), dto.getIdCardNo(), finalCheck.size()); |
| | | |
| | | if (CollectionUtils.isEmpty(finalCheck)) { |
| | | patArchiveService.insertPatArchive(patArchive); |
| | | log.info("【processPatientArchive】✓ 新增患者档案成功,patientno={}, id={}", |
| | | patArchive.getPatientno(), patArchive.getId()); |
| | | } else { |
| | | // 其他线程已经插入,直接使用已有记录 |
| | | existingArchives = finalCheck; |
| | | patArchive.setId(existingArchives.get(0).getId()); |
| | | patArchive.setNotrequiredFlag(existingArchives.get(0).getNotrequiredFlag()); |
| | | patArchive.setNotrequiredreason(existingArchives.get(0).getNotrequiredreason()); |
| | | log.info("【processPatientArchive】档案已被其他线程创建,使用已有记录,id={}", patArchive.getId()); |
| | | } |
| | | } catch (org.springframework.dao.DuplicateKeyException e) { |
| | | log.error("【processPatientArchive】患者档案已存在(并发插入),跳过:patientno={}, idcardno={}", patArchive.getPatientno(), patArchive.getIdcardno()); |
| | | log.warn("【processPatientArchive】患者档案已存在(并发插入异常),跳过:patientno={}, idcardno={}", |
| | | patArchive.getPatientno(), patArchive.getIdcardno()); |
| | | // 并发插入场景,重新查询获取已存在的记录 |
| | | PatArchive queryRetry = new PatArchive(); |
| | | queryRetry.setPatientno(patArchive.getPatientno()); |
| | | if (StringUtils.isNotEmpty(patArchive.getIdcardno())) { |
| | | queryRetry.setIdcardno(patArchive.getIdcardno()); |
| | | } |
| | | existingArchives = patArchiveService.selectPatArchiveList(queryRetry); |
| | | if (CollectionUtils.isNotEmpty(existingArchives)) { |
| | | patArchive.setId(existingArchives.get(0).getId()); |
| | | patArchive.setNotrequiredFlag(existingArchives.get(0).getNotrequiredFlag()); |
| | | patArchive.setNotrequiredreason(existingArchives.get(0).getNotrequiredreason()); |
| | | log.info("【processPatientArchive】从异常恢复,获取已有档案,id={}", patArchive.getId()); |
| | | } |
| | | } |
| | | } else { |
| | |
| | | patArchive.setNotrequiredFlag(existingArchives.get(0).getNotrequiredFlag()); |
| | | patArchive.setNotrequiredreason(existingArchives.get(0).getNotrequiredreason()); |
| | | patArchiveService.updateArchive(patArchive); |
| | | log.info("【processPatientArchive】更新患者档案,患者编号:{}", patArchive.getPatientno()); |
| | | log.info("【processPatientArchive】✓ 更新患者档案,patientno={}, id={}", |
| | | patArchive.getPatientno(), patArchive.getId()); |
| | | } |
| | | |
| | | return patArchive; |