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

Spring Boot 2.7.7更新Account时密码被置为null的问题求助

Spring Boot 2.7.7 账户更新时密码被置为null的问题排查与解决

问题原因

  • @JsonProperty(access = JsonProperty.Access.WRITE_ONLY)仅控制JSON序列化逻辑:它只限制后端不把密码字段返回给前端,但前端发送更新请求时,请求体里不会携带password字段,Spring MVC将请求体转换为Account对象时,password字段会被默认赋值为null。
  • 直接调用accountRepository.save(account)执行的是全量更新:前端传来的Account对象属于detached状态(未被JPA持久化上下文管理),JPA会将对象的所有字段(包括为null的password)覆盖写入数据库,导致原有密码被清空。

解决方案

方案1:先查后更,拷贝非空属性

从数据库查询原有账户实体,仅将前端传来的非null属性(或指定需要更新的属性)拷贝到原有实体,再执行保存操作,避免覆盖密码字段。
示例代码:

public Account updateAccount(Long id, Account account) throws CustomException {
    // 查询数据库中已存在的账户
    Account existingAccount = accountRepository.findById(id)
            .orElseThrow(() -> new CustomException("账户不存在"));
    
    // 使用BeanUtils拷贝非null属性,忽略password和id等不需要更新的字段
    BeanUtils.copyProperties(account, existingAccount, "password", "id");
    
    // 也可以手动赋值需要更新的字段,比如title
    // existingAccount.setTitle(account.getTitle());
    
    return accountRepository.save(existingAccount);
}

注意:使用BeanUtils时需明确忽略敏感字段,避免误覆盖其他不需要更新的内容。

方案2:使用JPA自定义更新查询

在Repository层编写仅更新指定字段的JPQL或SQL,直接执行部分字段更新,完全不涉及密码字段。
示例代码:

@Repository
public interface IAccountRepository extends JpaRepository<Account, Long> {
    @Modifying
    @Query("UPDATE Account a SET a.title = :title WHERE a.id = :id")
    int updateTitleById(@Param("id") Long id, @Param("title") String title);
}

服务层调用该方法:

public void updateAccountTitle(Long id, String title) throws CustomException {
    int affectedRows = accountRepository.updateTitleById(id, title);
    if (affectedRows == 0) {
        throw new CustomException("账户不存在或未修改");
    }
}

方案3:结合@DynamicUpdate实现动态更新

在Account实体类上添加@DynamicUpdate注解,JPA会生成仅包含变化字段的更新SQL,但需配合“先查后更”的方式使用,否则前端传来的null字段仍会被更新。
修改实体类:

@Entity
@Builder
@Data
@NoArgsConstructor
@AllArgsConstructor
@Table(name = "accounts")
@DynamicUpdate // 添加该注解
public class Account extends BaseEntity implements Serializable {
    // ... 其他字段
    
    @JsonProperty(access = JsonProperty.Access.WRITE_ONLY)
    @Column(name = "password")
    private String password;
}

服务层仍使用“先查后更”的逻辑,此时JPA生成的SQL只会更新被修改的字段,不会涉及密码字段。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.02 20:30:42