JPA之update操作 --save()方法更新部分字段,指定字段忽略不进行修改

背景

在进行关系型数据库保存操作时,如果要修改的数据存在,则进行修改;否则,进行保存。
但如果数据修改时,仅修改我们想要修改的字段时,需要做一层拦截处理

业务

在业务中有一张CustomerCompare表
该表是用于保存多数据源对应的各自字段值信息
当前对数表字段有:
1、数据源1的status1,tierName1,points1
2、数据源2的status2,tierName2,points2
3、数据源3的status3,tierName3,points3
如果数据源1的数据变更时,在入库保存时仅修改第1点的相关字段
数据源2同理如上
数据源3同理如上

具体操作

1、先查询库中数据是否存在

2、如果数据存在,仅修改当前需要修改的字段,忽略不需要修改的字段

3、进行保存或更新操作

基于第2点,需要写一个过滤的工具类,工具类代码如下

/**
 * @创建人 Eric.Lu
 * @创建时间 2023/9/5
 * @描述
 */
public class UpdateUtil {

	/**
	 * 所有为空值的属性都不copy
	 *
	 * @param source
	 * @param target
	 */
	public static void copyNullProperties(Object source, Object target) {
		if (Objects.isNull(target)) {
			return;
		}
		BeanUtils.copyProperties(source, target, getNullField(source));
	}

	public static void copyPropertiesIgnoreFields(Object source, Object target, String... ignoreProperties) {
		if (Objects.isNull(source)) {
			return;
		}
		BeanUtils.copyProperties(source, target, ignoreProperties);
	}

	/**
	 * 获取属性中为空的字段
	 *
	 * @param target
	 * @return
	 */
	private static String[] getNullField(Object target) {
		BeanWrapper beanWrapper = new BeanWrapperImpl(target);
		PropertyDescriptor[] propertyDescriptors = beanWrapper.getPropertyDescriptors();
		Set<String> notNullFieldSet = new HashSet<>();
		for (PropertyDescriptor p : propertyDescriptors) {
			String name = p.getName();
			Object value = beanWrapper.getPropertyValue(name);
			if (Objects.isNull(value)) {
				notNullFieldSet.add(name);
			}
		}
		String[] notNullField = new String[notNullFieldSet.size()];
		return notNullFieldSet.toArray(notNullField);
	}
}

保存入库部分代码如下


public void save(AllCustomerCompareMssql allCustomerCompareMssql) {
		AllCustomerCompareMssql old = allCustomerCompareMssqlRepository.findOne(allCustomerCompareMssql.getCustomerSID());
		//将上游传来的不为空参数(也即是要修改值)copy覆盖原始对象属性值
		//并且指定一些字段不做修改,禁止修改其它数据源的字段
		String[] ignoreProperties = {
				"esCustomerType", "esStatus", "esAvailablePoints", "esBirthday",
				"mssqlCustomerType", "mssqlStatus", "mssqlAvailablePoints", "mssqlBirthday"
		};
		UpdateUtil.copyPropertiesIgnoreFields(allCustomerCompareMssql, old, ignoreProperties);
		allCustomerCompareMssqlRepository.save(old);
    }

UpdateUtil 工具类解析

底层使用的事Spring–BeanUtils工具类copyProperties方法

Spring的BeanUtils工具类的用法简介

我们经常需要将不同的两个对象实例进行属性复制,比如将DO对象进行属性复制到DTO,这种转换最原始的方式就是手动编写大量的 get/set代码,很繁琐。为了解决这一痛点,就诞生了一些方便的类库,常用的有 Apache的 BeanUtils,Spring的 BeanUtils, Dozer,Orika等拷贝工具。

由于Apache的BeanUtils的性能很差,强烈不建议使用。阿里巴巴Java开发规约插件上也明确指出:“Ali-Check | 避免用Apache Beanutils进行属性的copy。”

Spring的BeanUtils方法

方法说明
BeanUtils.copyProperties(source, target);source对应的对象成员赋值给target对应的对象成员
BeanUtils.copyProperties(source, target, “id”, “time”);忽略拷贝某些字段。本处是忽略:id与time

Spring的BeanUtils方法注意事项

  • 浅拷贝: 对基本数据类型进行值传递,对引用数据类型,使用其引用地址,不拷贝其内容,此为浅拷贝
  • 深拷贝: 对基本数据类型进行值传递,对引用数据类型,创建一个新的对象,并复制其内容,此为深拷贝。

浅拷贝与深拷贝

浅拷贝只复制指向某个对象的指针,而不复制对象本身,新旧对象还是共享同一块内存。但深拷贝会另外创造一个一模一样的对象,新对象跟原对象不共享内存,修改新对象不会改到原对象。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
如果在使用JPA的`save`方法时,`@Update`注解无法正工作,可能是因为该注解只在更新实体时才会生效,而不是在保存新实体时`@UpdateTimestamp`注只会在执行更新更新时间戳字段。 你想要在保存实体时也更新时间戳字段,你可以尝试以下两种方法: 1. 在保存实体之前手动设置时间戳字段的值:在调用`save`方法之前,手动设置时间戳字段的值为当前时间。例如: ```java YourEntity entity = new YourEntity(); entity.setUpdateTime(new Date()); // 设置时间戳字段的值为当前时间 repository.save(entity); ``` 这样可以确保在保存新实体时,时间戳字段的值也会被更新。 2. 使用JPA的`@PrePersist`注解:你可以在实体类中使用`@PrePersist`注解,在保存实体之前自动设置时间戳字段的值。例如: ```java @Entity public class YourEntity { // ... @Temporal(TemporalType.TIMESTAMP) @UpdateTimestamp private Date updateTime; @PrePersist protected void onCreate() { updateTime = new Date(); // 在保存实体之前设置时间戳字段的值为当前时间 } // ... } ``` 使用`@PrePersist`注解可以确保在执行保存操作之前自动更新时间戳字段。 请注意,以上方法适用于在保存新实体时更新时间戳字段。如果你需要在更新实体时更新时间戳字段,`@UpdateTimestamp`注解应该正常工作。如果问题仍然存在,请检查JPA配置和数据库支持,确保没有其他因素干扰时间戳字段更新
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值