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

如何高效更新JPA Entity实体,无需逐个判断非空字段手动赋值

方案1:使用Spring自带的BeanUtils工具类(快速实现,适合中小项目)

无需引入额外依赖,通过反射自动识别非空字段完成赋值,注意不要导错包,必须使用Spring自带的org.springframework.beans.BeanUtils,不要用Apache Commons的同名工具类。

首先编写通用工具方法获取对象所有为null的属性名:

import org.springframework.beans.BeanWrapper;
import org.springframework.beans.BeanWrapperImpl;
import java.beans.PropertyDescriptor;
import java.util.HashSet;
import java.util.Set;

public static String[] getNullPropertyNames (Object source) {
    final BeanWrapper src = new BeanWrapperImpl(source);
    PropertyDescriptor[] pds = src.getPropertyDescriptors();
    Set<String> emptyNames = new HashSet<>();
    for(PropertyDescriptor pd : pds) {
        Object srcValue = src.getPropertyValue(pd.getName());
        // 如果需要把空字符串也判定为不更新,可修改判断条件为 srcValue == null || "".equals(srcValue)
        if (srcValue == null) {
            emptyNames.add(pd.getName());
        }
    }
    return emptyNames.toArray(new String[0]);
}

改造后的更新方法:

import org.springframework.beans.BeanUtils;

public void updateCustomer(Customer customer) {
    Customer existingCustomer = customerRepository.findById(customer.getId())
                                                  .orElseThrow(() -> new RuntimeException("对应客户不存在"));
    // 拷贝属性时忽略所有传入对象为null的字段
    BeanUtils.copyProperties(customer, existingCustomer, getNullPropertyNames(customer));
    customerRepository.save(existingCustomer);
}

方案2:使用MapStruct(高性能,适合中大型、高并发场景)

MapStruct是编译期生成映射代码,没有反射开销,性能和手写代码一致,同时会在编译期校验字段映射合法性,避免运行时异常。

首先引入Maven依赖:

<dependency>
    <groupId>org.mapstruct</groupId>
    <artifactId>mapstruct</artifactId>
    <version>1.5.5.Final</version>
</dependency>
<dependency>
    <groupId>org.mapstruct</groupId>
    <artifactId>mapstruct-processor</artifactId>
    <version>1.5.5.Final</version>
    <scope>provided</scope>
</dependency>

编写映射接口:

import org.mapstruct.Mapper;
import org.mapstruct.MappingTarget;
import org.mapstruct.NullValuePropertyMappingStrategy;

// 配置null值属性不参与映射,自动注册为Spring Bean
@Mapper(componentModel = "spring", nullValuePropertyMappingStrategy = NullValuePropertyMappingStrategy.IGNORE)
public interface CustomerMapper {
    // 把源对象的非空字段更新到目标对象上
    void updateNonNullField(Customer source, @MappingTarget Customer target);
}

改造后的业务代码:

@Autowired
private CustomerMapper customerMapper;

public void updateCustomer(Customer customer) {
    Customer existingCustomer = customerRepository.findById(customer.getId())
                                                  .orElseThrow(() -> new RuntimeException("对应客户不存在"));
    customerMapper.updateNonNullField(customer, existingCustomer);
    customerRepository.save(existingCustomer);
}

可选优化:配合JPA @DynamicUpdate注解

在Customer实体类上加@DynamicUpdate注解,JPA生成更新SQL时只会包含实际被修改的字段,不会全字段更新,可进一步降低数据库写入开销、减少行锁冲突:

@Entity
@DynamicUpdate
public class Customer {
    @Id 
    @GeneratedValue(strategy = GenerationType.AUTO)
    public long id;
    public String name;
    public String phone;
    //...
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.02 12:48:02