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

news2024/11/26 12:16:57

报错信息如下:
当使用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<>();
}
@Test
    public 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>
        <!-- 数据库方言 -->
        <property
                name="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.coloradmin.cn/o/616046.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

如何在Windows 10中创建屏幕保护程序设置快捷方式

屏幕保护程序是指你在电脑上未处于活动状态并等待指定时间后,电脑屏幕上显示的动态图片或图案。 屏幕保护程序最初用于保护旧的单色显示器免受损坏,但现在它们主要是通过提供密码保护来个性化你的电脑或增强其安全性的一种方式。 一、右键单击或按住桌面上的空白区域,然后…

linuxOPS基础_linux umask

1、什么是umask umask表示创建文件时的默认权限&#xff08;即创建文件时不需要设置而天生的权限&#xff09; 例如&#xff1a; root用户下&#xff0c;touch a &#xff0c;文件a的默认权限是644 普通用户下&#xff0c;touch b &#xff0c;文件b的默认权限是664 644和…

AOSP+WSL+adb搭建安卓开发ebpf环境

0.写在前面 首先我们要明白&#xff0c;安卓的AOSP包含了海量的代码&#xff0c;他包含了包括了&#xff1a; 1.不同架构下&#xff08;音响&#xff0c;手机&#xff0c;电视等等各种基于安卓的设备&#xff09;的上层应用 2.Java API Framework&#xff08;大部分安卓开发…

叉积求二维空间两直线交点以及过两点的直线数学原理

叉积求二维空间两直线交点以及过两点的直线数学原理_wang.chen.xue的博客-CSDN博客

ThreeJS教程:屏幕坐标转标准设备坐标

推荐&#xff1a;将 NSDT场景编辑器 加入你的3D工具链 3D工具集&#xff1a; NSDT简石数字孪生 屏幕坐标转标准设备坐标 在讲解下节课鼠标点击选中模型之前&#xff0c;先给大家讲解下坐标系的问题。 获取鼠标事件坐标 先来了解一些&#xff0c;普通的web前端相关知识。 鼠…

aop原理

1. 使用 1.1 依赖 <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-aop</artifactId></dependency>1.2 定义切面类 定义一个切面类&#xff0c;指定增强的方法&#xff0c;方法前两个注解必须…

Axure教程—滚动加载(中继器 )

本文将教大家如何用AXURE中的中继器制作滚动加载效果 一、效果介绍 如图&#xff1a; 预览地址&#xff1a;https://awjggr.axshare.com 下载地址&#xff1a;https://download.csdn.net/download/weixin_43516258/87867798?spm1001.2014.3001.5503 二、功能介绍 向下滚动鼠…

联想YOGA Pro14s电脑运行时总是蓝屏怎么办?

联想YOGA Pro14s电脑运行时总是蓝屏怎么办&#xff1f;最近有用户在使用电脑的时候&#xff0c;电脑总是会自动变成蓝屏&#xff0c;导致自己的操作中断。那么遇到这个情况要怎么去进行问题的解决呢&#xff1f;接下来我们来看看以下的详细解决方法分享吧。 准备工作&#xff1…

通过python封装关键词搜索1688商品列表数据API、1688商品列表API接口、1688API接口

1688商品详情接口是一种用于访问阿里巴巴旗下的批发市场平台上的商品列表信息的API接口。通过该接口&#xff0c;可以获取商品的详细信息&#xff0c;包括商品名称、规格、价格、描述、图片等。这些信息对于买家和卖家来说都非常重要&#xff0c;可以帮助他们更好地了解商品&am…

MyBatisPlus3-条件查询和映射问题(字段、表名)

1. 条件查询三种方式 条件查询多用第三种&#xff1b; 链式写表示且的关系&#xff0c;中间加上or()表示或的关系&#xff1b; 给出相应示例代码&#xff1a; Test public void testGetList(){//方式一&#xff1a;按条件查询/*QueryWrapper<User> userQueryWrapper new…

基于WebGL的智慧化工三维可视化管理系统

前言 作为全球化学品第一生产大国&#xff0c;我国危险化学品规模总量大、涉及品种多、应用范围广、管理链条长、安全风险高&#xff0c;历来是防范化解重大安全风险的重点领域。 危险化学品领域频繁发生的典型事故&#xff0c;暴露出传统安全风险管控手段问题突出。 建设背景…

【裸机驱动LED】使用汇编代码驱动LED(一)—— 寄存器解析篇

为了后续使用C语言驱动LED&#xff0c;事先学习汇编代码驱动LED&#xff0c;有如下好处&#xff1a; 熟悉一些基本的汇编语法了解驱动LED的基本流程了解驱动LED需要用到哪些寄存器作为一个初学者&#xff0c;可以锻炼自己阅读开发文档的能力 本文的主要目的是了解驱动LED的基…

【手撕Spring源码】SpringBoot启动过程中发生了什么?

文章目录 SpringBoot启动过程启动详解启动演示启动过程总结 SpringBoot启动过程 启动详解 SpringBoot的启动分为两个部分&#xff1a; 构造SpringApplication执行run方法 接下来我们先来看看构造方法里面都做了什么事情。 第一步&#xff1a;记录 BeanDefinition 源 大家知…

Jenkins配置邮件通知+钉钉通知,任务构建状态随时掌握

1.前言 Hello&#xff0c;各位小伙伴&#xff0c;大家好&#xff01;&#xff01;&#xff01; 在前面的文章中&#xff0c;我们实现了用Maven项目任务和Pipeline流水线任务来完成对项目的自动化部署。 DockerJenkinsGitee自动化部署maven项目 DockerJenkinsGiteePipeline部…

0001欧几里得算法

首先我们先了解欧几里得这个人。俗话说&#xff1a;不了解一个人&#xff0c;很难走进他的思想。欧几里得是约公元前330年~公元前275年的古希腊数学家&#xff0c;被称为“几何之父”。《几何原本》就是他的著作。而欧几里得算法是《几何原本》中的一个用于求两个数的最大公约数…

以AI为灯,照亮医疗放射防护监管盲区

相信绝大部分人都有在医院拍X光片的经历&#xff0c;它能够让医生更方便快速地找出潜在问题&#xff0c;判断病人健康状况&#xff0c;是医疗诊断过程中的常见检查方式。但同时X射线也是一把双刃剑&#xff0c;它的照射量可在体内累积&#xff0c;对人体血液白细胞有杀伤力&…

mysql加索引,数据库卡死

公司的一个内部项目&#xff0c;由于突然导入了几十万的数据&#xff0c;数据量翻了一倍&#xff0c;导致了某个页面打开很慢。通过sql日志看到主要是由于慢查询引起的&#xff0c;通过explain这个sql&#xff0c;发现主要是由于这个SQL没有命中索引&#xff0c;进行了全表扫描…

原型模式的用法

文章目录 一、原型模式的用法1.1 介绍1.2 结构1.3 原型模式类图1.4 实现1.4.1 克隆的分类1.4.2 代码 1.5 "三好学生"奖状案例1.5.1 "三好学生"奖状类图1.5.2 代码 1.6 深、浅克隆的区分1.6.1 浅克隆1.6.2 深克隆 一、原型模式的用法 1.1 介绍 用一个已经…

STL(结)

STL&#xff08;结&#xff09; map存储结构基本操作equal_range遍历方式 插入 multimapsetunordered_mapmap和无序map的异同mapunordered_map map 存储结构 map容器的底层存储是一个红黑树&#xff0c;遍历方式都是按照中序遍历的方式进行的。 int main() {std::map<int…

数组降维

写一个函数&#xff0c;打印数组内的内容&#xff0c;代码为&#xff1a; #include<stdio.h>void show_arr(int arr[], int num) {int i 0;for (i 0; i < num; i){printf("%d ", arr[i]);}printf("\n"); } int main() {int arr[] { 1,2,3,4,5…