如何使用Spring Projections更新@Entity注解标记的实体?
核心结论
Spring Data JPA 的 Projection 属于只读视图,不能用于修改并持久化现有实体,你提到的直接修改Projection属性后调用save的方式无法生效。
原因说明
Projection 本质是 Spring 框架动态生成的接口代理对象,不属于 JPA 持久化上下文管理的实体实例,CrudRepository的save方法仅支持处理标注了@Entity的实体类对象,传入Projection实例要么触发类型匹配错误,要么不会产生任何持久化效果。
仅更新指定字段、保留其余字段原值的实现方案
你的需求不需要依赖Projection,有两种成熟的实现方式:
方案1:使用@DynamicUpdate实现动态更新(兼容性最好)
在实体类上添加@DynamicUpdate注解,JPA生成更新SQL时会自动只包含被修改过的字段,其余字段会保留数据库中的原有值:
@Entity @DynamicUpdate // 新增该注解开启动态更新 public class Person { @Id private long id; private String firstname, lastname, age; // 省略getter、setter方法 }
业务逻辑实现如下:
@Transactional public void update() { Person p = repository.findByLastname("Doe"); p.setLastname("test"); repository.save(p); // 执行时仅会生成更新lastname字段的SQL,不改动其他字段 } interface PersonRepository extends CrudRepository<Person, Long> { Person findByLastname(String lastname); }
方案2:自定义更新语句(性能更高)
如果不需要查询实体的其他属性,可以直接在Repository层定义自定义更新方法,通过JPQL语句直接更新指定字段,不需要先查询实体:
interface PersonRepository extends CrudRepository<Person, Long> { Person findByLastname(String lastname); // 新增单字段更新方法 @Modifying @Transactional @Query("UPDATE Person p SET p.lastname = :newLastname WHERE p.lastname = :oldLastname") int updateLastnameByOldLastname(String oldLastname, String newLastname); }
业务层直接调用即可:
public void update() { repository.updateLastnameByOldLastname("Doe", "test"); }
内容的提问来源于stack exchange,提问作者membersound
相关产品推荐
相关产品推荐

