SpringBoot+springDataJpa实现单表字段动态部分更新
写在前面
所谓的动态部分更新是指:并非对数据记录的所有字段整体更新,而是知道运行时才确定哪个或者哪些字段需要被更新。
1)Spring Data Jpa对于Entity的更新,是对数据表中Entity对应的除主键外的数据记录的所有字段整体更新,
而不是仅仅更新前端传入的字段或者那些发生了变化的字段;
2)repository.save()的逻辑是:如果不存在Entity对应的数据记录则执行插入操作,否则则执行更新操作。同时,
在执行更新操作之前,此方法还会执行一步查询操作。源码如下:
@Transactional
@Override
public <S extends T> S save(S entity) { if (entityInformation.isNew(entity)) {
em.persist(entity);
return entity;
} else {
return em.merge(entity);
}
}
3)对于字段更新时,如果使用@Query注解,通过写原生SQL的方法,确实可以实现字段的部分更新,但是使用@Query注解无法很好地实现字段的动态部分更新。
4)使用@DynamicUpdate注解,通过在Entity实体类上添加此注解,再结合repository.save()方法进行字段更新,此方法的确具有可行性,但是仍存在一个问题:当字段值为null值时,Jpa会将null值与原值作比较,如果原值不为null,那么原值将会被覆盖为null。
针对此问题,如何解决呢,这里提供一种方法。
对于动态部分更新,可以在@DynamicUpdate注解的基础上,可以书写一个Jpa工具类来避免null值对于动态部分更新的影响。
这里给出一个示例代码:
import org.springframework.beans.BeanUtils;
import org.springframework.beans.BeanWrapperImpl; import java.beans.PropertyDescriptor;
import java.util.stream.Stream; public class JpaUtil {
public static void copyNotNullProperties(Object src,Object target){
BeanUtils.copyProperties(src,target,getNullPropertyNames(src));
} private static String[] getNullPropertyNames(Object object) {
final BeanWrapperImpl wrapper = new BeanWrapperImpl(object);
return Stream.of(wrapper.getPropertyDescriptors())
.map(PropertyDescriptor::getName)
.filter(propertyName -> wrapper.getPropertyValue(propertyName) == null)
.toArray(String[]::new);
}
}
下面根据示例代码进行整合。
1> 数据准备
CREATE TABLE `tb_user` (
`id` int(32) NOT NULL AUTO_INCREMENT COMMENT '主键Id',
`name` varchar(20) DEFAULT NULL COMMENT '用户名',
`age` int(10) DEFAULT NULL COMMENT '年龄',
`email` varchar(255) DEFAULT NULL COMMENT '邮箱',
`address` varchar(255) DEFAULT NULL COMMENT '地址',
`create_time` datetime DEFAULT NULL COMMENT '创建时间',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=9 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
INSERT INTO `tb_user` VALUES (1, '张三', 22, '123456@qq.com', '北京市', '2020-02-16 13:18:21');
INSERT INTO `tb_user` VALUES (2, '李四', 23, '243456@qq.com', '天津市', '2020-02-16 13:18:58');
INSERT INTO `tb_user` VALUES (3, '王五', 22, '123597@qq.com', '重庆市', '2020-02-16 13:18:58');
INSERT INTO `tb_user` VALUES (4, '赵六', 21, '565345@qq.com', '武汉市', '2020-02-16 13:18:58');
INSERT INTO `tb_user` VALUES (5, '钱七', 24, '375654@qq.com', '杭州市', '2020-02-16 13:18:58');
INSERT INTO `tb_user` VALUES (6, '孙八', 26, '977842@qq.com', '上海市', '2020-02-16 13:18:58');
INSERT INTO `tb_user` VALUES (7, '周九', 24, '345342@qq.com', '深圳市', '2020-02-16 13:18:58');
INSERT INTO `tb_user` VALUES (8, '郑十', 25, '645564@qq.com', '广州市', '2020-02-16 13:18:58');
2> 创建工程,导入依赖
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.2.0.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.darren</groupId>
<artifactId>springjpa-demo</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>springjpa-demo</name>
<description>Demo project for Spring Boot</description> <properties>
<java.version>1.8</java.version>
</properties> <dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency> <dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies> <build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build> </project>
3> 配置Application.yml文件
spring:
datasource:
url: jdbc:mysql:///springboottest?characterEncoding=utf8&useSSL=false&serverTimezone=GMT%2b8
username: root
password: root
driver-class-name: com.mysql.cj.jdbc.Driver
jpa:
hibernate:
ddl-auto: update
show-sql: true
generate-ddl: true
4> 创建entity实体类
import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.Data;
import org.hibernate.annotations.DynamicUpdate;
import org.springframework.format.annotation.DateTimeFormat; import javax.persistence.*;
import java.util.Date; @Entity
@Data
@Table(name = "tb_user")
@DynamicUpdate
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id; private String name; private Integer age; private String email; private String address; @Column(name = "create_time")
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date createTime;
}
5> 创建Repository接口
import com.darren.springjpademo.entity.User;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
import org.springframework.stereotype.Repository; @Repository
public interface UserRepository extends JpaRepository<User,Integer>, JpaSpecificationExecutor<User> {
}
6> 创建Service层接口及其实现类
6.1 创建service层接口
import com.darren.springjpademo.entity.User; import java.util.List; public interface UserService {
/**
* 查询所有用户信息
* @return
*/
List<User> queryList(); /**
* 更新用户信息
* @param user
* @return
*/
String updateUser(User user);
}
6.2 创建ServiceImpl实现类
import com.darren.springjpademo.repository.UserRepository;
import com.darren.springjpademo.entity.User;
import com.darren.springjpademo.service.UserService;
import com.darren.springjpademo.uitls.JpaUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service; import java.util.List;
import java.util.Optional; @Service
public class UserServiceImpl implements UserService {
@Autowired
private UserRepository userRepository; @Override
public List<User> queryList() {
return userRepository.findAll();
} @Override
public String updateUser(User user) {
User user = new User();
user.setId(1);
user.setName("张三");
user.setAddress("北京");
if(user.getId() != null) {
Optional<User> originalUser = userRepository.findById(user.getId());
if (originalUser.isPresent()) {
JpaUtil.copyNotNullProperties(user, originalUser.get());
}
}
userRepository.save(user);
return user.getId()+" "+user.getName();
}
}
7> 创建Controller层
import com.darren.springjpademo.entity.User;
import com.darren.springjpademo.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*; import java.util.List; @RestController
@RequestMapping("/user")
public class UserController {
@Autowired
private UserService userService; /**
* 查询所有的用户信息
* @return
*/
@GetMapping("/queryList")
public List<User> queryList(){
return this.userService.queryList();
} /**
* 更新用户信息
* @param user
* @return
*/
@PutMapping("/updateUser")
public ResponseEntity<String> updateUser(@RequestBody User user){
String result = userService.updateUser(user);
return ResponseEntity.ok(result);
}
}
SpringBoot+springDataJpa实现单表字段动态部分更新的更多相关文章
- MySQL 按照数据库表字段动态排序 查询列表信息
MySQL 按照数据库表字段动态排序 查询列表信息 背景描述 项目中数据列表分页展示的时候,前端使用的Table组件,每列自带对当前页的数据进行升序或者降序的排序. 但是客户期望:随机点击某一列的时候 ...
- Django框架之第二篇--app注册、静态文件配置、form表单提交、pycharm连接数据库、django使用mysql数据库、表字段的增删改查、表数据的增删改查
本节知识点大致为:静态文件配置.form表单提交数据后端如何获取.request方法.pycharm连接数据库,django使用mysql数据库.表字段的增删改查.表数据的增删改查 一.创建app,创 ...
- 关于解决SpringDataJpa框架实体类表字段创建顺序与数据库表字段展示顺序不一致的问题
今天在公司的项目开发中,遇到一个问题: 后端对象实体类中写入字段顺序与数据库中的存储顺序不一致. 仔细观察到数据库中的表字段的排序方式是按照拼音字母的顺序abcdef......来存储的 而我的实体类 ...
- tp数据表字段缓存
在维护一个tp写的项目,因为需要在产品表product中增加了一个字段status,但是不论如何就是无法给status赋值,查了资料才发现,原来是tp的数据表字段缓存在搞鬼. 在runtime> ...
- spring boot学习(7) SpringBoot 之表单验证
第一节:SpringBoot 之表单验证@Valid 是spring-data-jpa的功能: 下面是添加学生的信息例子,要求姓名不能为空,年龄大于18岁. 贴下代码吧: Student实体: ...
- MySQL 基本语法(1.表字段操作,2表记录管理 3.运算符管理4.SQL查询 5.约束6.索引
.表字段的操作 .语法:alter table 表名 执行动作; .添加字段(add) .添加到末尾 alter table 表名 add 字段名 数据类型; .添加到第一列 alter table ...
- 132_Power BI之建模必备要素&Power Query之数据表字段名称管理
博客:www.jiaopengzi.com 焦棚子的文章目录 请点击下载附件 一.背景 近段时间比较忙,也没有看到很好的DAX素材,很久没有更新文章了,刚好有时间就来凑个热闹. 今天主题是Power ...
- mysql 数据库 表字段添加表情兼容
项目中的几个需要支持Emoji表情符号,手机自带的表情,其实添加也很简单: 1 修改数据库 配置my.cnf init-connect='SET NAMES utf8mb4' ...
- 为了解决mysqlbing翻译表字段问题而分析frm文件(持续更新)
出处:kelvin19840813 的博客 http://www.cnblogs.com/kelvin19840813/ 您的支持是对博主最大的鼓励,感谢您的认真阅读.本文版权归作者所有,欢迎转载,但 ...
随机推荐
- 论文阅读笔记(八)【IEEEAccess2019】:High-Resolution and Low-Resolution Video Person Re-Identification: A Benchmark
Introduction (1)Motivation: 监控视频中的行人,有的比较清晰,有的因为距离较远非常模糊. 在高低分辨率方面的行人重识别缺乏数据集和研究. (2)Contribution: ① ...
- Linux命令——细节
echo -n 不换行输出 echo -e 处理特殊字符 若字符串中出现以下字符,则特别加以处理,而不会将它当成一般文字输出: \a 发出警告声: \b 删除前一个字符: \c 最后不加上换行符号: ...
- hyper-v虚拟机不能访问外网的解决方案
直接说解决方案,将虚拟机的一张网卡改为旧版网络适配器即可.具体原因还不可知. 延申一下,一般应该使用的交换机,是“外部”类型即可.
- Linux的VMware虚拟机无法上网问题
很多时候,Linux无法上网,不管改成nat模式还是主机模式都不行.这时候可以选择进行重置: 首先点击编辑,之后点击虚拟网络编辑器, 然后移除VMnet0和VMnet8网络,点击确定: 然后再打开虚拟 ...
- MySQL的排序(order by)
MySQL的排序(order by) 1.降序(DESC) 2.升序(ASC) 1. 降序(DESC) 完整代码: SELECT `学号`,`考试日期`,`考试成绩` FROM `表2`ORDER B ...
- docker-储存持久化
docker容器不适合存放数据,重要的数据要用外部卷存储,容器可以挂载真实机目录或者共享存储为卷 储存卷映射 docker run -itd -v 真实机目录:容器目录 镜像:标签 可以做一台nfs服 ...
- D - How Many Answers Are Wrong HDU - 3038【带权并查集】
How Many Answers Are Wrong Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Ja ...
- @RendSection{"scripts",require:false}的作用
MVC视图中,Javascripts代码被放于下面的Razor代码中(@section Scripts{}). 好处:在视图进行JavaScript编程时,是一个很好的实践,在共享视图(_Layout ...
- [AtCoder Code Festival 2017 QualB C/At3574] 3 Steps - 二分图染色,结论
给你一个n个点m条边的无向图,进行以下操作 如果存在两个点u和v,使得从u走三步能恰好到达v,那么在u和v之间连接一条边 重复这个操作直到不能再连接新的边,问最后有多少条边? n, m <= 1 ...
- normalization flow
from Eric Jang Normalizing flows transform simple densities (like Gaussians) into rich complex distr ...