springboot 中 @DynamicUpdate 注解无效解决方案
遇到的问题
项目中使用 jpa,以前没用过,所以踩坑在所难免。
在使用过程中,要更新一条记录的某个字段,更新成功以后,发现整条记录只剩下我更新的那个字段,其他的全部为空了。
瞬间明白,这种更新是全覆盖,针对每个字段 update,实体类没赋值的字段,也直接将空值 set 过去了。
首先,用getById()查出原值,然后赋值想要修改的新的字段值(copy克隆赋值)
思路很简单,这里主要贴一下对象复制的代码。将数据库中查出的对象称为target,包含要修改的字段的对象称为source,当然,最后我们save的是修改之后的target。
附上克隆对象的工具:BeanCopyUtil
import org.springframework.beans.BeanUtils;
import org.springframework.beans.BeanWrapper;
import org.springframework.beans.BeanWrapperImpl;
import java.util.HashSet;
import java.util.Set;
/**
* created by xxx 2022/9/29
*/
public class BeanCopyUtil {
//source中的非空属性复制到target中
public static void beanCopy(T source, T target) {
BeanUtils.copyProperties(source, target, getNullPropertyNames(source));
}
//source中的非空属性复制到target中,但是忽略指定的属性,也就是说有些属性是不可修改的(个人业务需要)
public static void beanCopyWithIngore(T source, T target, String... ignoreProperties) {
String[] pns = getNullAndIgnorePropertyNames(source, ignoreProperties);
BeanUtils.copyProperties(source, target, pns);
}
public static String[] getNullAndIgnorePropertyNames(Object source, String... ignoreProperties) {
Set emptyNames = getNullPropertyNameSet(source);
for (String s : ignoreProperties) {
emptyNames.add(s);
}
String[] result = new String[emptyNames.size()];
return emptyNames.toArray(result);
}
public static String[] getNullPropertyNames(Object source) {
Set emptyNames = getNullPropertyNameSet(source);
String[] result = new String[emptyNames.size()];
return emptyNames.toArray(result);
}
public static Set getNullPropertyNameSet(Object source) {
final BeanWrapper src = new BeanWrapperImpl(source);
java.beans.PropertyDescriptor[] pds = src.getPropertyDescriptors();
Set emptyNames = new HashSet<>();
for (java.beans.PropertyDescriptor pd : pds) {
Object srcValue = src.getPropertyValue(pd.getName());
if (srcValue == null) emptyNames.add(pd.getName());
}
return emptyNames;
}
}
有了这个方法,在修改的时候就比较方便了,我的做法是在实体类中加一个方法:
public void copy(Task task) {
BeanCopyUtil.beanCopyWithIngore(task, this);
}
然后在service或者controller中update方法中调用:
@Transactional
public Task updateTask(Task task) {
try {
if (task.getId() == null) {
return null;
}
Task saveTask = taskRepository.getById(task.getId());
saveTask.copy(task);
return taskRepository.saveAndFlush(saveTask);
} catch (Exception e) {
throw new CustomException(SERVER_ERROR, e);
}
}