当用springdatajpa自带save()进行更新操作时,会先在底层执行merge()的一个动作,而执行merge动作时根据entiy标签里面的@ID,也就是主键来区分的,所以正确的更新方式是先把对应的entiy查询出来,然后在更新某个字段。
这就引申出一个问题,假如我们直接使用实体对象来接收更新参数,所以我们并不知道哪个字段被更改掉。这就涉及到新老数据的对比操作。虽然我们可以直接使用BeanUtils.copyProperties(oldEntiy,newEntiy);来进行数据拷贝,但在不注意情况下就会出现丢失数据的情况。
如何防止这种情况呢。这里可以运用java的反射机制来处理这种情况。话不多说,直接上代码:
import java.beans.IntrospectionException;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.math.BigDecimal;
import java.util.Date;
/**
* @author lqyang
* @Title: SPRING-JPA-DATA 更新操作时 校验数据是否为空 解决处理BeanUtils.copyProperties(obj1,obj2);为空数据的处理
* @date 2018/8/217:00
*/
public class FieldUtil<T> {
private T entity;
public FieldUtil(T entity){
this.entity = entity;
}
/**
* 使用案例:
* SysUserEntity sysUserEntity = sysUserDao.findOne(user.getUserId());
* BeanUtils.copyProperties(sysUserEntity,user);
* if(sysUserEntity != null){
* for(Field f : user.getClass().getDeclaredFields()){
* f.setAccessible(true);
* if(f.get(user) == null){
* String name = f.getName();
* FieldUtil<SysUserEntity> fieldUtil = new FieldUtil<>(user);
* fieldUtil.doInitEntity(name,sysUserEntity);
* }
* }
* sysUserDao.save(user);
* }else {
* user.setUserId(StringUtil.uuid());
* sysUserDao.save(user);
* }
* @param methodName
* @param object
* @throws InvocationTargetException
* @throws IllegalAccessException
* @throws NoSuchFieldException
* @throws IntrospectionException
*/
public void doInitEntity(String methodName,Object object) throws InvocationTargetException, IllegalAccessException, NoSuchFieldException, IntrospectionException {
//根据传入的属性名称构造属性的set方法名
String str = methodName.substring(0, 1).toUpperCase()+methodName.substring(1);
String methodNameNew = "set"+str;
Method[] methods = entity.getClass().getMethods();
for(Method method:methods){
//如果方法同名则执行该方法(不能用于实体中有重载方法的情况)
if(methodNameNew.equals(method.getName())){
Class<?>[] clazz = method.getParameterTypes();
String type = clazz[0].getName();
if(type.equalsIgnoreCase("java.lang.String")){
Field field = object.getClass().getDeclaredField(methodName);
field.setAccessible(true);
if(field.get(object) != null){
method.invoke(entity,(String)field.get(object));
}
}
else if(type.equalsIgnoreCase("java.util.Date")){
Field field = object.getClass().getDeclaredField(methodName);
field.setAccessible(true);
if(field.get(object) != null){
method.invoke(entity, (Date)field.get(object));
}
}
else if(type.equalsIgnoreCase("java.lang.Integer")){
Field field = object.getClass().getDeclaredField(methodName);
field.setAccessible(true);
if(field.get(object) != null){
method.invoke(entity, new Integer((Integer) field.get(object)));
}
}
else if(type.equalsIgnoreCase("java.lang.Float")){
Field field = object.getClass().getDeclaredField(methodName);
field.setAccessible(true);
if(field.get(object) != null){
method.invoke(entity, new Float((Float) field.get(object)));
}
}
else if(type.equalsIgnoreCase("java.lang.Boolean")){
Field field = object.getClass().getDeclaredField(methodName);
field.setAccessible(true);
if(field.get(object) != null){
method.invoke(entity, new Boolean((Boolean) field.get(object)));
}
}
else if(type.equalsIgnoreCase("java.math.BigDecimal")){
Field field = object.getClass().getDeclaredField(methodName);
field.setAccessible(true);
if(field.get(object) != null){
method.invoke(entity, (BigDecimal) field.get(object));
}
}
}
}
}
}
使用案例
@Transactional(rollbackFor = Exception.class)
public void updateUser(SysUserEntity user)throws Exception {
SysUserEntity sysUserEntity = sysUserDao.findOne(user.getUserId());
//BeanUtils.copyProperties(sysUserEntity,user);
if(sysUserEntity != null){
for(Field f : user.getClass().getDeclaredFields()){
f.setAccessible(true);
if(f.get(user) == null){
String name = f.getName();
FieldUtil<SysUserEntity> fieldUtil = new FieldUtil<>(user);
fieldUtil.doInitEntity(name,sysUserEntity);
}
}
sysUserDao.save(user);
}
}