码迷,mamicode.com
首页 > 编程语言 > 详细

SpringBoot+springDataJpa实现单表字段动态部分更新

时间:2020-02-21 18:21:48      阅读:216      评论:0      收藏:0      [点我收藏+]

标签:实体   依赖   查询   use   user   source   ide   weight   false   

写在前面

所谓的动态部分更新是指:并非对数据记录的所有字段整体更新,而是知道运行时才确定哪个或者哪些字段需要被更新。

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实现单表字段动态部分更新

标签:实体   依赖   查询   use   user   source   ide   weight   false   

原文地址:https://www.cnblogs.com/cndarren/p/12342082.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!