Spring Data JDBC中如何防止@CreatedBy与@CreatedDate字段在更新时被修改
解决Spring Data JDBC更新时createdBy/createdDate被置为null的问题
嘿,这个问题我之前也碰到过,Spring Data JDBC确实没提供JPA那种updatable=false的注解支持,不过有几个靠谱的解决方案可以帮你搞定更新时覆盖created字段的问题:
方案1:使用实体回调(Entity Callback)控制更新逻辑
这是Spring Data JDBC官方推荐的扩展方式,通过实现BeforeUpdateCallback,在更新操作执行前保留原实体的创建信息。
创建一个回调类并注册为Spring Bean:
@Component public class AuditEntityUpdateCallback implements BeforeUpdateCallback<AuditEntity> { @Override public AuditEntity onBeforeUpdate(AuditEntity entity, AggregateChange aggregateChange) { // 从AggregateChange中获取数据库里的原始实体状态 Optional<Object> originalEntityOpt = aggregateChange.getEntity().getOriginalValue(); if (originalEntityOpt.isPresent()) { AuditEntity originalAudit = (AuditEntity) originalEntityOpt.get(); // 将原始的createdBy和createdOn赋值回当前实体,避免被覆盖为null entity.setCreatedBy(originalAudit.getCreatedBy()); entity.setCreatedOn(originalAudit.getCreatedOn()); } return entity; } }
原理:当执行更新时,Spring Data JDBC会加载数据库中已有的实体数据,我们通过回调把原始的创建信息重新赋值给待更新的实体,这样最终生成的SQL更新语句就会带上原有值,而不是null。
方案2:在实体setter中添加保护逻辑
通过手动实现createdBy和createdOn的setter方法,只允许初始赋值,后续修改(包括设置为null)会被忽略。
修改你的AuditEntity类:
@Data // Lombok public class AuditEntity { @JsonIgnore @LastModifiedDate private String updatedOn; @JsonIgnore @LastModifiedBy private String updatedBy; @JsonIgnore @CreatedDate private String createdBy; @JsonIgnore @CreatedBy private String createdOn; // 手动实现createdBy的setter,仅允许初始设置 public void setCreatedBy(String createdBy) { if (this.createdBy == null) { this.createdBy = createdBy; } // 已有值时不做任何操作,避免被覆盖 } // 同理实现createdOn的setter public void setCreatedOn(String createdOn) { if (this.createdOn == null) { this.createdOn = createdOn; } } }
原理:当更新操作试图修改createdBy或createdOn时,setter会忽略新的赋值(包括null),从而保留最初插入时的数值。
方案3:自定义Repository实现合并更新
创建一个通用的基础Repository,在更新时先查询原实体,仅复制需要修改的字段,跳过创建信息字段。
定义基础Repository接口:
public interface BaseRepository<T, ID> extends CrudRepository<T, ID> { default T update(ID id, T updatedEntity) { // 查询数据库中的原始实体 T originalEntity = findById(id) .orElseThrow(() -> new IllegalArgumentException("Entity with id " + id + " not found")); // 使用BeanUtils复制属性,排除createdBy和createdOn字段 BeanUtils.copyProperties(updatedEntity, originalEntity, "createdBy", "createdOn"); // 保存合并后的实体 return save(originalEntity); } }
然后让你的业务Repository继承这个BaseRepository,之后更新时调用update()方法而非默认的save()方法即可。
方案推荐
优先选择方案1,因为它完全贴合Spring Data JDBC的设计理念,不需要修改业务代码的调用方式,也无需手动处理实体合并逻辑,是最优雅的解决方案。
内容的提问来源于stack exchange,提问作者Ravi
相关产品推荐
相关产品推荐

