Hibernate+Lombok进行表与表之间关系时插入数据时栈溢出

news/2024/11/16 0:50:00/

报错信息如下:
当使用Hibernate和Lombok处理表与表之间的关系时,在插入数据时可能会遇到栈溢出错误。这篇博客将详细讨论此问题的原因,并提供解决办法。在这里插入图片描述

标题: Hibernate+Lombok进行表与表之间关系时插入数据时栈溢出

问题背景

Hibernate是一个Java持久化框架,通过对象关系映射(ORM)的方式,将Java对象映射到关系型数据库中的表。Lombok是一个Java库,通过自动代码生成的方式,简化了Java类的编写。

在使用Hibernate和Lombok时,我们通常使用注解来描述表与表之间的关系,例如一对多、多对一等关联关系。然而,有时在插入数据时会遇到栈溢出错误,这可能导致开发者困惑和疑惑。


源代码:

@Data
public class LinkMan {private int uid;private String username;private String tel;private String gender;Customer customer;}
@Data
public class Customer {private int cid;private String name;private String address;Set<LinkMan> linkManSet = new HashSet<>();
}
@Testpublic void relationTest() {Session session = HibernateUtil.getCurrSession();Transaction transaction = session.beginTransaction();Customer customer = new Customer();customer.setName("腾讯");customer.setAddress("深圳");Customer customer1 = new Customer();customer1.setName("阿里巴巴");customer1.setAddress("杭州");LinkMan linkMan = new LinkMan();linkMan.setUsername("李彦宏");linkMan.setTel("110");linkMan.setGender("男");LinkMan linkMan1 = new LinkMan();linkMan1.setUsername("陈迪凯");linkMan1.setTel("119");linkMan1.setGender("男");LinkMan linkMan2 = new LinkMan();linkMan2.setUsername("马化腾");linkMan2.setTel("120");linkMan2.setGender("女");LinkMan linkMan3 = new LinkMan();linkMan3.setUsername("张小龙");linkMan3.setTel("114");linkMan3.setGender("男");customer.getLinkManSet().add(linkMan);customer.getLinkManSet().add(linkMan1);linkMan.setCustomer(customer);linkMan1.setCustomer(customer);customer1.getLinkManSet().add(linkMan2);customer1.getLinkManSet().add(linkMan3);linkMan2.setCustomer(customer1);linkMan3.setCustomer(customer1);//保存数据session.save(customer);session.save(customer1);session.save(linkMan);session.save(linkMan1);session.save(linkMan2);session.save(linkMan3);transaction.commit();session.close();}
<?xml version="1.0" encoding="utf-8" ?>
<!-- 引入核心配置文件约束 -->
<!DOCTYPE hibernate-configuration PUBLIC"-//Hibernate/Hibernate Configuration DTD 3.0//EN""http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">
<hibernate-configuration><!-- 配置hibernate核心配置文件 --><session-factory><!-- 1、数据库信息 必需 --><property name="hibernate.connection.driver_class">com.mysql.cj.jdbc.Driver</property><property name="hibernate.connection.url">jdbc:mysql://localhost:3306/hibernate_study?serverTimezone=GMT&amp;useSSL=false&amp;characterEncoding=utf8</property><property name="hibernate.connection.username">root</property><property name="hibernate.connection.password">root</property><!-- 2、hibernate信息 非必需 --><!-- 在控制台输出hibernate底层生成的SQL语句 --><property name="show_sql">true</property><!-- 格式化hibernate底层生成的SQL语句 --><property name="format_sql">true</property><!-- 数据库方言 --><propertyname="hibernate.dialect">org.hibernate.dialect.MySQL8Dialect</property><!-- 设置事务的隔离级别值为1:事务隔离级别为“读未提交”值为2:事务隔离级别为“读已提交”值为3:事务隔离级别为“可重复读”值为4:事务隔离级别为“可串行化”--><property name="hibernate.connection.isolation">4</property><!-- session绑定本地线程 --><property name="current_session_context_class">thread</property><!-- hibernate自动创建数据库表,如果表已经存在,则更新表,如果不存在,则创建表格 --><property name="hibernate.hbm2ddl.auto">update</property><!-- 3、引用hibernate映射关系配置文件,mapping标签必须在property标签后面 必需 --><mapping resource="mapper/user.hbm.xml"/><mapping resource="mapper/customer.hbm.xml"/><mapping resource="mapper/linkman.hbm.xml"/></session-factory>
</hibernate-configuration>
<?xml version="1.0" encoding="utf-8" ?>
<!-- 引入映射关系配置文件约束 -->
<!DOCTYPE hibernate-mapping PUBLIC"-//Hibernate/Hibernate Mapping DTD 3.0//EN""http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping><!-- 配置对象和数据库表之间的映射关系name:实体类的全路径名table:数据库表的名称--><class name="icu.chiou.entity.User" table="tb_user"><!-- 配置主键映射关系name:实体类中的属性名column:数据库表中主键名称,column属性可以省略,如果省略,则自动生成的数据库表主键名称和实体类名称一致--><id name="id" column="id"><!-- 主键生成策略 --><generator class="native"/></id><!-- 配置其他属性的映射关系 --><property name="username" column="username"/><property name="password" column="password"/></class>
</hibernate-mapping>

查证问题

经过多方查证,发现栈溢出错误与Lombok的@Data注解有关。@Data注解是Lombok提供的一个实用注解,它自动生成了一些常用方法,包括equals()hashCode()toString()等。然而,问题出现在hashCode()方法的生成上。

在默认情况下,Lombok的@Data注解会重写hashCode()方法,并使用所有字段来计算哈希码。这其中包括了关联对象的字段,从而导致在计算哈希码时发生循环调用,最终导致栈溢出错误:

  • 调用this.getLinkManSet();。
  • linkmanset里面又包含customer
  • 调用this.getCustomer();里面又包含linkman

为了更好地理解这个问题,我们可以查看编译后的类文件。编译后的类文件会展示出Lombok生成的代码。以下是一个示例:


Customer.class

public int hashCode() {int PRIME = true;int result = 1;result = result * 59 + this.getCid();Object $name = this.getName();result = result * 59 + ($name == null ? 43 : $name.hashCode());Object $address = this.getAddress();result = result * 59 + ($address == null ? 43 : $address.hashCode());Object $linkManSet = this.getLinkManSet();result = result * 59 + ($linkManSet == null ? 43 : $linkManSet.hashCode());return result;}

LinkMan.class

public int hashCode() {int PRIME = true;int result = 1;result = result * 59 + this.getUid();Object $username = this.getUsername();result = result * 59 + ($username == null ? 43 : $username.hashCode());Object $tel = this.getTel();result = result * 59 + ($tel == null ? 43 : $tel.hashCode());Object $gender = this.getGender();result = result * 59 + ($gender == null ? 43 : $gender.hashCode());Object $customer = this.getCustomer();result = result * 59 + ($customer == null ? 43 : $customer.hashCode());return result;}

从上述示例中可以看出,hashCode()方法中使用了关联对象otherEntityhashCode()方法,这可能导致循环调用,最终触发栈溢出错误。

解决办法

针对上述问题,我们可以采取以下解决办法:

  1. 使用@Getter@Setter代替@Data@Data注解是Lombok提供的一个快捷注解,它包含了@Getter@Setter@EqualsAndHashCode@ToString等注解

的功能。但在处理关联对象时,我们可以避免使用@Data注解,而是手动添加@Getter@Setter注解。这样就能避免在hashCode()方法中出现循环调用的问题。

修改后的示例代码如下:

@Getter
@Setter
public class LinkMan {private int uid;private String username;private String tel;private String gender;Customer customer;
}

通过手动添加@Getter@Setter注解,我们可以避免在hashCode()方法中引发循环调用的问题,从而解决栈溢出错误。

结论

在使用Hibernate和Lombok处理表与表之间的关系时,特别是在涉及关联对象的hashCode()方法中,需要小心使用Lombok的@Data注解。通过使用@Getter@Setter注解,我们可以避免栈溢出错误,并确保对象关系映射的正确性。

探讨了栈溢出错误的原因和解决办法后,我们希望这篇博客能帮助到遇到类似问题的开发者们。

如果你在使用Hibernate和Lombok过程中遇到其他问题,或者有其他相关的疑问,欢迎在评论区留言,我们将竭诚为您解答。


http://www.ppmy.cn/news/244230.html

相关文章

戴尔15-7572怎样设置硬盘启动?

1、开机按F1进bios。 2、进入bios页面&#xff0c;按键盘→按键右移至Startup&#xff0c;然后向下移至Primary Boot Sequence。 3、看到硬盘&#xff0c;将需要设置的硬盘调整为第一启动。 4、方向键向下&#xff0c;移到需要调整的硬盘&#xff0c;按数字键盘的符号&#…

戴尔DELL 笔记本 改WIN7 BIOS 设置详解

博主出品必属精品 其他参考&#xff1a;改WIN7 BIOS 关键点设置详解 链接&#xff1a; http://blog.csdn.net/qq_33350731/article/details/76136189 按以下修改好支持 GPTUEFI启动一键安装WIN7 &#xff08;第三步不改才支持一键安装&#xff09; 图片参考百度 1,重启按F2 进…

dell 7527 raid50 故障处理

dell 7525 raid50 单盘故障&#xff0c;无法自动重建问题 {1}生产故障表现 单块raid5中&#xff0c;某块磁盘出现故障&#xff0c;raid出现降级&#xff0c;重建插入后&#xff0c;查看磁盘状态&#xff0c;未进入自动重建状态。 {2}生产环境描述 生产环境下&#xff0c;de…

【C++】——list的介绍及模拟实现

文章目录 1. 前言2. list的介绍3. list的常用接口3.1 list的构造函数3.2 iterator的使用3.3 list的空间管理3.4 list的结点访问3.5 list的增删查改 4. list迭代器失效的问题5. list模拟实现6. list与vector的对比7. 结尾 1. 前言 我们之前已经学习了string和vector&#xff0c…

Android RK3588-12 hdmi-in Camera方式支持NV24格式

hdmi-in Camera方式支持NV24格式 modified: hardware/interfaces/camera/device/3.4/default/ExternalCameraDevice.cpp modified: hardware/interfaces/camera/device/3.4/default/ExternalCameraDeviceSession.cpp diff --git a/hardware/interfaces/camera/device/3.4…

sid,eld,sidd dataset介绍,dng图像处理

文章目录 SID dataset1. SID dataset 概述2. SID 读取和显示代码3. 一些示例 SIDD datasetELD datasetDNG camera pipeline SID dataset 1. SID dataset 概述 SID 是Learning to See in the Dark 论文中提出的暗光raw数据集 其中包括两个相机的拍摄数据 Sony alpha7S II 和 …

【vue中修改swiper样式】

原文&#xff1a;https://www.cnblogs.com/fightjianxian/p/11920913.html vue中修改swiper样式 问题&#xff1a;vue单文件组件中无法修改swiper样式。 解决 1. 单文件组件中&#xff1a;新增一个style 不加scoped 让它最终成为全局样式。只在其中操作swiper的样式。 <s…

华为OD机试真题 Java 实现【分糖果】【2022Q2 200分】,附详细解题思路

一、题目描述 小明从糖果盒中随意抓一把糖果&#xff0c;每次小明会取出一半的糖果分给同学们。 当糖果不能平均分配时&#xff0c;小明可以选择从糖果盒中&#xff08;假设盒中糖果足够&#xff09;取出一个糖果或放回一个糖果。 小明最少需要多少次&#xff08;取出、放回…