详解SpringBoot实现JPA的save方法不更新null属性

网友投稿 752 2023-01-16


详解SpringBoot实现JPA的save方法不更新null属性

序言:直接调用原生Save方法会导致null属性覆盖到数据库,使用起来十分不方便。本文提供便捷方法解决此问题。

核心思路

如果现在保存某User对象,首先根据主键查询这个User的最新对象,然后将此User对象的非空属性覆盖到最新对象。

核心代码

直接修改通用JpaRepository的实现类,然后在启动类标记此实现类即可。

一、通用CRUD实现类

public class SimpleJpaRepositoryImpl extends SimpleJpaRepository {

private final JpaEntityInformation entityInformation;

private final EntityManager em;

@Autowired

public SimpleJpaRepositoryImpl(JpaEntityInformation entityInformation, EntityManager entityManager) {

super(entityInformation, entityManager);

this.entityInformation = entityInformation;

this.em = entityManager;

}

/**

* 通用save方法 :新增/选择性更新

*/

@Override

@Transactional

public S save(S entity) {

//获取ID

ID entityId = (ID) entityInformation.getId(entity);

Optional optionalT;

if (StringUtils.isEmpty(entityId)) {

String uuid = UUID.randomUUID().toString();

//防止UUID重复

if (findById((ID) uuid).isPresent()) {

uuid = UUID.randomUUID().toString();

}

//若ID为空 则设置为UUID

new BeanWrapperImpl(entity).setPropertyValue(entityInformation.getIdAttribute().getName(), uuid);

//标记为新增数据

optionalT = Optional.empty();

} else {

//若ID非空 则查询最新数据

optionalT = findById(entityId);

}

//获取空属性并处理成null

String[] nullProperties = getNullProperties(entity);

//若根据ID查询结果为空

if (!optionalT.isPresent()) {

em.persist(entity);//新增

return entity;

} else {

//1.获取最新对象

T target = optionalT.get();

//2.将非空属性覆盖到最新对象

BeanUtils.copyProperties(entity, target, nullProperties);

//3.更新非空属性

em.merge(target);

return entity;

}

}

/**

* 获取对象的空属性

*/

private static String[] getNullProperties(Object src) {

//1.获取Bean

BeanWrapper srcBean = new BeanWrapperImpl(src);

//2.获取Bean的属性描述

PropertyDescriptor[] pds = srcBean.getPropertyDescriptors();

//3.获取Bean的空属性

Set properties = new HashSet<>();

for (PropertyDescriptor propertyDescriptor : pds) {

String propertyName = propertyDescriptor.getName();

Object propertyValue = srcBean.getPropertyValue(propertyName);

if (StringUtils.isEmpty(propertyValue)) {

srcBean.setPropertyValue(propertyName, null);

properties.add(propertyName);

}

}

return properties.toArray(new String[0]);

}

}

二、启动类

@EnableJpaRepositories(value = "com.hehe.repository", repositoryBaseClass = SimpleJpaRepositoryImpl.class)

@SpringBootApplication

public class JpaApplication {

public static void main(String[] args) {

SpringApplication.run(JpaApplication.class, args);

}

}

三、实体类和通用Save

@Entity

@Table(name = "T_USER")

@jsonIgnoreProperties({"handler","hibernateLazyInitializer"})

public class User {

@Id

private String userId;

private String username;

private String password;

//省略GET/SET

}

public interface UserRepository extends JpaRepository {

}

四、配置文件 application.yml

spring:

datasource:

url: jdbc:mysql://localhost:3306/socks?useSSL=false

username: root

password: root

driver-class-name: com.mysql.jdbc.Driver

五、数据库脚本

drop table if exists t_user;

create table t_user (

user_id varchar(50),

username varchar(50),

password varchar(50)

);

insert into t_user values ('1', 'admin', 'admin');

insert into t_user values ('2', 'yizhiwazi', '123456');

六、测试代码

@RestController

public class UserController {

@Autowired

private UserRepository userRepository;

@RequestMapping("/")

public User get() {

userRepository.save(new User("1", "", null));

return userRepository.findById("1").get();

}fqwbjSa

}

整体结构图

在实际项目中,可以直接复制SimpleJpaRepositoryImpl使用,并不影响原有的其它API。


版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:在Spring boot的项目中使用Junit进行单体测试
下一篇:实现接口重写方法快捷键(java重写接口方法)
相关文章

 发表评论

暂时没有评论,来抢沙发吧~