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 中使用对象的坑及源码排查思路

相关推荐
身如柳絮随风扬1 天前
Dubbo 与 Spring Cloud 终极对比:RPC 框架 vs 微服务生态
spring cloud·rpc·dubbo
一个有温度的技术博主1 天前
Spring Cloud 入门与实战:从架构拆分到核心组件详解
spring·spring cloud·架构
uNke DEPH1 天前
SpringCloud Gateway 集成 Sentinel 详解 及实现动态监听Nacos规则配置实时更新流控规则
spring cloud·gateway·sentinel
慕容卡卡2 天前
你所不知道的RAG那些事
java·开发语言·人工智能·spring boot·spring cloud
dLYG DUMS2 天前
Spring Cloud Data Flow 简介
后端·spring·spring cloud
Ken_11152 天前
SpringCloud系列(61)--Nacos之服务配置中心的介绍与使用
spring cloud
Ken_11152 天前
SpringCloud系列(62)--Nacos之命名空间、分组和DataID三者之间的关系
spring cloud
Ken_11152 天前
SpringCloud系列(63)--Nacos读取不同配置之DataID配置方案
spring cloud
Devin~Y3 天前
从Spring Boot到Spring AI:音视频AIGC内容社区Java大厂面试三轮连环问(含Kafka/Redis/安全/可观测性答案)
java·spring boot·redis·spring cloud·kafka·spring security·resilience4j
qqty12173 天前
springcloud springboot nacos版本对应
spring boot·spring·spring cloud