Hibernate踩坑之 update覆盖更新问题

前言

因为之前一直用的mybatis plus 做业务 后来换工作后项目是Hibernate 所以在使用上避免不了踩坑
下面就是我整理的一些常见的坑点

一、aupdate覆盖更新问题

项目中使用 jpa,以前没用过,所以踩坑在所难免。
在使用过程中,要更新一条记录的某个字段,更新成功以后,发现整条记录只剩下我更新的那个字段,其他的全部为空了。
瞬间明白,这种更新是全覆盖,针对每个字段 update,实体类没赋值的字段,也直接将空值 set 过去了。

看到网上解决方法是加标注@DynamicUpdate 设置为ture 本以为已经解决,可问题好像并没有那么简单
一番测试下来发现null还是会覆盖
后来看了这个老哥的评论恍然大悟
Hibernate踩坑之 update覆盖更新问题_第1张图片

解决方案

BeanCopyUtil:

import ch.qos.logback.core.joran.util.beans.BeanUtil;
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 2018/7/21
 */
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, "taskNum", "createPerson");
    }

然后在service中update方法中调用:

    @Transactional
    public Task updateTask(Task task) {
        try {
            if (task.getId() == null) {
                return null;
            }
            Task saveTask = taskRepository.findOne(task.getId());
            saveTask.copy(task);
            return taskRepository.saveAndFlush(task);
        } catch (Exception e) {
            throw new CustomException(SERVER_ERROR, e);
        }
    }
总结

采用Hibernate会遇到各种各样问题 以上只是踩坑一点 后续会继续更新 解决方案是采用BeanCopyUtil覆盖原对象的方法,感觉还不错可以试试

你可能感兴趣的:(Hibernate)