Spring Data JPA 踩过的坑实录

前言

游戏中台一直在使用spring 全家桶, 本文会左右使用Spring Data JPA的坑点记录总结 · 主要给大家总结介绍了关于使用Spring JPA注意事项及踩过的坑。

案例1: 为什么只调用了 org.springframework.data.repository.CrudRepository#findById(ID id) 却触发了update 的操作?

明明只是一次普通的查询操作,但却带出了update 的SQL打印,感觉很神奇。

bash 复制代码
2024-01-12 15:36:41.607 INFO [VD5FrKZc][XNIO-1 task-4][ResourceRegistryStandardImpl.java:94] - com.mysql.cj.jdbc.ClientPreparedStatement: select * from `project` project0_ where project0_.`id`=52
2024-01-12 15:36:41.613 INFO [VD5FrKZc][XNIO-1 task-4][ResourceRegistryStandardImpl.java:94] - com.mysql.cj.jdbc.ClientPreparedStatement: update `project` set `add_time`='2024-01-08 21:40:58', `modify_time`='2024-01-12 14:17:12', `activity`='POPULAR', ********' where `id`=52

通过断点调试发现org.hibernate.event.spi.FlushEntityEvent的dirtyProperties属性位有发生变化,是第24位:

然后去查看24位的属性通过FlushEntityEvent.propertyValues 发现对应的entity属性为:

java 复制代码
    @ApiModelProperty(value = "任务列表", position = 14)
    @Column(name = "task_list", nullable = false)
    @Convert(converter = TaskConvert.class)
    private List<TaskDTO> taskList = new ArrayList<>();

到这里,我们大概能猜到,估计是@Convert做值转化时导致的,

顺藤摸瓜,org.hibernate.type.TypeHelper#findDirty()→org.hibernate.type.AbstractType#isEqual()→ Objects.equals( x, y )

后续到最核心的部分发现比较两个字段的对象是否相等来判断是否有变化(isDirty),我们debug发现,两个对象并不相等,我们的对象是JSON转换的ArrayList,而自动会用到ArrayList的equals方法。其equals方法是通过比较元素的equals和hashcode,不相同的原因找到了,因为我们没有重写对象的equals和hashCode方法所以导致的不相等;重写对应的方法重新debug发现update语句消失了;

JPA 中调用 save 后会将对象deepCopy一次快照来做为持久化对象,后续 flush(事物提交)的时候hibernate需要检测出哪些持久化entity被修改过,flush的dirty check过程其实就是比对持久化entity和快照是否一致,不一致就去发udpate语句。而是否相等则是通过 Objects.equals 方法来比较;deepCopy属性的时候普通String等基本类型Class已经帮我们实现好了,而自定义的类则没有对应的方法来比较是否相等。导致JPA以为对象发生变化而执行更新操作;

虽然 hibernate调用save后默认是持久化状态,我们只需要调用entity的 setXXX() 方法,JPA就会默认帮我们update。通过 isDirty() 来检测是否字段有变化

将@Convert使用的对象,都加上equals和hashCode方法。或者可以使用lombok提供的注解(@Data或@EqualsAndHashCode)

java 复制代码
@EqualsAndHashCode
public class TaskDTO {
    @ApiModelProperty(value = "任务", example = "日有效数据>=50")
    private String name;
  }

参考链接:
JPA Entity 中 @Convert 中使用对象的坑及源码排查思路

相关推荐
源码集结号13 小时前
一套智慧工地云平台源码,支持监管端、项目管理端,Java+Spring Cloud +UniApp +MySql技术开发
java·mysql·spring cloud·uni-app·源码·智慧工地·成品系统
AAA修煤气灶刘哥1 天前
监控摄像头?不,我们管这个叫优雅的埋点艺术!
java·后端·spring cloud
yunmi_1 天前
Spring Cloud Netfilx -- Ribbon:负载均衡工具(代码示例)
spring cloud·ribbon·maven·负载均衡
还是鼠鼠2 天前
《黑马商城》微服务保护-详细介绍【简单易懂注释版】
java·spring boot·spring·spring cloud·sentinel·maven
唐僧洗头爱飘柔95272 天前
【SpringCloud(1)】初识微服务架构:创建一个简单的微服务;java与Spring与微服务;初入RestTemplate
java·spring·spring cloud·微服务·架构·resttemplate·java微服务技术栈
m0_651593913 天前
位置透明性、Spring Cloud Gateway与reactor响应式编程的关系
java·spring cloud·系统架构·gateway
yunmi_3 天前
微服务,Spring Cloud 和 Eureka:服务发现工具
java·spring boot·spring cloud·微服务·eureka·架构·服务发现
唐僧洗头爱飘柔95273 天前
【SpringCloud(2)】微服务注册中心:Eureka、Zookeeper;CAP分析;服务注册与服务发现;单机/集群部署Eureka;连接注册中心
spring cloud·微服务·zookeeper·eureka·服务发现·集群部署·服务注册
aloha_7894 天前
顺丰科技java面经准备
java·开发语言·spring boot·科技·spring·spring cloud
森林-4 天前
Spring Cloud Netflix Ribbon:微服务的客户端负载均衡利器
spring cloud·微服务·ribbon·负载均衡