jpa中只有save方法并没有update方法,那他是怎么实现更新的呢,
首先对于save方法,他会先根据id在数据库里查询,如果没查到数据就会insert一条数据;
如果查到数据,就会update一条数据,但是如果要存入的对象有的字段没有赋值(为null),他就会把null也会插入数据库,那原来这条数据有的字段有值也会被覆盖掉,为了避免这种情况发生,就要做出调整。
一.继承SimpleJpaRepository,改写save方法
package cn.qingsec.test.report.repository; import cn.qingsec.test.report.utils.BeanUtils; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.jpa.repository.support.JpaEntityInformation; import org.springframework.data.jpa.repository.support.SimpleJpaRepository; import javax.persistence.EntityManager; import java.util.Optional; /** * @Author: Liu * @Date: 2023/08/30 * @Description: */ @Slf4j public class ZeusJpaRepository<T, ID> extends SimpleJpaRepository<T, ID> { private JpaEntityInformation<T, ?> jpaEntityInformation; /** * Creates a new {@link ZeusJpaRepository} to manage objects of the given {@link JpaEntityInformation}. * * @param entityInformation must not be {@literal null}. * @param entityManager must not be {@literal null}. */ @Autowired public ZeusJpaRepository(JpaEntityInformation<T, ?> entityInformation, EntityManager entityManager) { super(entityInformation, entityManager); this.jpaEntityInformation = entityInformation; } /** * 覆盖原来实现,不更新null字段 * @author 隐 * @date 2020-03-16 * @param entity * @param <S> * @return */ @Override public <S extends T> S save(S entity) { ID id = (ID) jpaEntityInformation.getId(entity); if (id != null) { Optional<T> op = findById(id); if (op.isPresent()) { T t = op.get(); BeanUtils.copyPropertiesWithoutNull(entity, t); entity = (S) t; } } return super.save(entity); } }
二.重写BeanUtils
package cn.qingsec.test.report.utils; import org.springframework.beans.FatalBeanException; import java.beans.PropertyDescriptor; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.lang.reflect.Modifier; /** * @Author: Liu * @Date: 2023/08/30 * @Description: */ public class BeanUtils extends org.springframework.beans.BeanUtils { /** * bean copy不复制null值 * @author 隐 * @date 2018-11-10 * @param source * @param target */ public static void copyPropertiesWithoutNull(Object source, Object target) { if(source == null || target == null){ return; } Class<?> actualEditable = target.getClass(); Class<?> sourceClass = source.getClass(); PropertyDescriptor[] targetPds = getPropertyDescriptors(actualEditable); for (PropertyDescriptor targetPd : targetPds) { if(targetPd.getWriteMethod() == null) { continue; } PropertyDescriptor sourcePd = getPropertyDescriptor(sourceClass, targetPd.getName()); if(sourcePd == null || sourcePd.getReadMethod() == null) { continue; } try { Method readMethod = sourcePd.getReadMethod(); if (!Modifier.isPublic(readMethod.getDeclaringClass().getModifiers())) { readMethod.setAccessible(true); } Object value = readMethod.invoke(source); setValue(target, targetPd, value); } catch (Exception ex) { throw new FatalBeanException("Could not copy properties from source to target", ex); } } } /** * 设置值到目标bean * @param target * @param targetPd * @param value * @throws IllegalAccessException * @throws InvocationTargetException */ private static void setValue(Object target, PropertyDescriptor targetPd, Object value) throws IllegalAccessException, InvocationTargetException { // 这里判断以下value是否为空 if (value != null) { Method writeMethod = targetPd.getWriteMethod(); if (!Modifier.isPublic(writeMethod.getDeclaringClass().getModifiers())) { writeMethod.setAccessible(true); } writeMethod.invoke(target, value); } } }
三.在启动类上加注解
@EnableJpaRepositories(repositoryBaseClass = ZeusJpaRepository.class)
四.加上注解
在实体类上加上注解
@DynamicUpdate @DynamicInsert