标签:实体 依赖 查询 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); } }
下面根据示例代码进行整合。
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‘);
<?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>
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
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; }
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> { }
import com.darren.springjpademo.entity.User; import java.util.List; public interface UserService { /** * 查询所有用户信息 * @return */ List<User> queryList(); /** * 更新用户信息 * @param user * @return */ String updateUser(User user); }
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(); } }
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