You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

SpringBoot中直接调用updatePatient方法时患者数据未加密问题

问题原因及解决方案

核心问题分析

直接调用updatePatient方法时未触发加密,本质是JPA实体生命周期事件未正确执行,或加密逻辑的条件判断存在漏洞,具体原因如下:


可能的原因

1. 实体监听器未与Patient实体关联

你的PatientListener类虽然实现了实体监听逻辑,但如果Patient实体类上没有添加@EntityListeners(PatientListener.class)注解,JPA不会识别这个监听器,@PreUpdate方法自然不会被触发,加密逻辑也就不会执行。

2. 事务配置错误导致@PreUpdate未触发

JPA的@PreUpdate事件仅在托管状态的实体发生变更,且EntityManager执行flush操作(事务提交时自动触发,或显式调用flush())时才会触发。你的代码存在两个问题:

  • updateByMrgPatient方法未添加@Transactional注解:查询出的Patient实体处于游离状态,修改属性后无法触发JPA的自动flush,@PreUpdate事件不会被触发。
  • 私有方法updatePatient上的@Transactional无效:Spring事务基于动态代理实现,private方法无法被代理增强,该注解不会生效,无法保证实体变更被JPA感知。

3. 加密逻辑的条件判断漏洞

当通过patientRepo.findByPatientId加载患者时,@PostLoad会解密数据,但不会修改isEncrypted字段的值(仍为true)。此时执行@PreUpdate方法时,会因为pc.getIsEncrypted()为true直接跳过加密,导致修改后的明文数据直接存入数据库。


解决方案

1. 关联实体监听器

在Patient实体类上添加@EntityListeners注解,确保JPA能触发监听逻辑:

@Entity
@EntityListeners(PatientListener.class)
public class Patient {
    // 实体字段、Getter/Setter等
}

2. 修复事务配置

给updateByMrgPatient方法添加@Transactional注解,保证实体处于托管状态,事务提交时自动触发flush和@PreUpdate事件:

@Override
@Transactional
public String updateByMrgPatient(UpdatePatientRequestDto updatePatientRequest, String patientId, int orgId, UpdateInitiatedTypeEnum updateInitiatedTypeEnum, String updateFrom){
    // 原有业务逻辑不变
}

同时移除私有方法updatePatient上的@Transactional注解,因为它在事务方法内部执行,无需重复配置。

3. 调整加密逻辑的状态标记

修改PatientListener中的@PostLoad和@PreUpdate方法,调整isEncrypted的状态,确保更新时触发加密:

@PostLoad
public void decryptRecord(Patient pc) {
    if (pc.getIsDecrypted()) {
        return;
    }
    EncryptDecryptService encryptDecryptService = determineEncryptionKey(pc);
    pc.setFirstName(encryptDecryptService.decryptString(pc.getFirstName()));
    // 其他字段解密逻辑...
    pc.setIsDecrypted(true);
    pc.setIsEncrypted(false); // 标记当前为明文状态,更新时触发加密
}

@PreUpdate
public void encryptRecordAfterUpdate(Patient pc) {
    if (pc.getIsEncrypted()) {
        return;
    }
    EncryptDecryptService encryptDecryptService = determineEncryptionKey(pc);
    pc.setFirstName(encryptDecryptService.encryptString(pc.getFirstName()));
    // 其他字段加密逻辑...
    pc.setIsEncrypted(true);
    pc.setIsDecrypted(false); // 重置解密状态
}

这样,实体加载解密后会被标记为未加密状态,更新时@PreUpdate就会执行加密逻辑,确保数据加密后存入数据库。


内容的提问来源于stack exchange,提问作者Destiel

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.28 06:24:54