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

