解决 mybatis 中相互关联的两种表数据在返回前端时一直循环查询,直到StackOverFlow报错

原代码设计:

一个用户有多个账户,是一对多的关系,用Collection集合关联;一个账户独属于一个用户,是一对一的关系,用association来关联;

UserMapper.xml

<mapper namespace="com.xuetu.springboot.mapper.UserMapper">

    <!-- 定义User的resultMap-->
    <resultMap id="userMap" type="user">
        <id property="id" column="id"></id>
        <result property="username" column="username"></result>
        <result property="address" column="address"></result>
        <result property="sex" column="sex"></result>
        <result property="birthday" column="birthday"></result>
        <!-- 配置user对象中accounts集合的映射 -->
        <collection property="accounts" ofType="account"
                    select="com.xuetu.springboot.mapper.AccountMapper.findAccountByUid"
                    column="id"
                    />
    </resultMap>

    <!-- 查询所有 -->
    <select id="findAll" resultMap="userMap">
        select * from user
    </select>

    <!-- 根据id查询用户 -->
    <select id="findById" parameterType="INT" resultMap="userMap">
        select * from user where id = #{uid}
    </select>

  AccountMapper.xml

<mapper namespace="com.xuetu.springboot.mapper.AccountMapper">
    <resultMap id="accountMap" type="account">
        <id property="id" column="id" />
        <result property="uid" column="uid" />
        <result property="money" column="money" />

        <association property="user" column="uid"
                     select="com.xuetu.springboot.mapper.UserMapper.findById"
                     />
    </resultMap>

    <select id="findAll" resultMap="accountMap">
        select * from account;
    </select>

    <select id="findAccountByUid" resultMap="accountMap" parameterType="INT">
        select * from account where uid = #{uid}
    </select>

  

问题发现:

使用懒加载的情况下,如果仅仅是在controller 中操作一些数据,不把数据返回前端,那么没有问题,但是如果需要把数据集合变成JSON格式 返回给前端就会无限循环的进行SQL语句的查询,因为collection中select 寻找的是对象,这个对象又进行一对一关联查询,获得的对象又进行一对多关联查询,以此循环往复,最终导致内存溢出。

希望的效果是:如果返回用户集合,这个集合中各个用户的只有一个账户列表(一对多),账户对象一对一指向为空

例如下列数据:

[{"id":41,"username":"老王","address":"北京","sex":"男","birthday":"2018-02-27T17:47:08.000+0000","accounts":[{"id":1,"uid":41,"money":1000.0,"user":null},{"id":3,"uid":41,"money":3000.0,"user":null}]},{"id":42,"username":"小二王","address":"北京金燕龙","sex":"女","birthday":"2018-03-02T15:09:37.000+0000","accounts":[]},{"id":43,"username":"小二九","address":"北京金燕龙","sex":"女","birthday":"2018-03-04T11:34:34.000+0000","accounts":[{"id":2,"uid":43,"money":2000.0,"user":null}]},{"id":45,"username":"传智播客","address":"北京金燕龙","sex":"男","birthday":"2018-03-04T12:04:06.000+0000","accounts":[]},{"id":46,"username":"老久","address":"北京","sex":"女","birthday":"2018-03-07T17:37:26.000+0000","accounts":[]},{"id":48,"username":"小马宝莉","address":"北京修正","sex":"女","birthday":"2018-03-08T11:44:00.000+0000","accounts":[]},{"id":51,"username":"李四","address":"广西南宁市","sex":"男","birthday":"2019-07-21T06:29:22.000+0000","accounts":[]},{"id":52,"username":"王五","address":"广西桂林市","sex":"男","birthday":"2019-07-20T08:19:50.000+0000","accounts":[]}]

解决办法:新增一个单独指向不关联的方法
UserMapper中:<!-- 定义User的resultMap-->
    <resultMap id="userMap" type="user">
        <id property="id" column="id"></id>
        <result property="username" column="username"></result>
        <result property="address" column="address"></result>
        <result property="sex" column="sex"></result>
        <result property="birthday" column="birthday"></result>
        <!-- 配置user对象中accounts集合的映射 -->
        <collection property="accounts" ofType="account"
                    select="com.xuetu.springboot.mapper.AccountMapper.findAccountByUidNoRel"
                    column="id"
                    />
    </resultMap>AccountMapper中:
<!--返回的对象是Account普通对象,而不是原来的accountMap-->
<select id="findAccountByUidNoRel" resultType="account" parameterType="INT">    select * from account where uid = #{uid}</select>

UserMapper.java接口中新增方法findByIdNoRel
@Repositorypublic interface UserMapper {    /**     * 查询所有用户,同时获取到用户下所有账户的信息     * @return     */    List<User> findAll();//    /**//     * 根据id查询用户信息//     * @param userId//     * @return//     */    User findById(Integer userId);

    User findByIdNoRel(Integer userId);

  这样返回的数据就不会一直相互请求关联下去了,这里需要忽略序列化的属性,使用@JsonIgnore,因为一对一指向为空

@JsonIgnoreProperties(value = {"handler"})
public class User implements Serializable {
private Integer id;private String username;private String address;
......

  最终可以将查询用户的结果集json格式 返回给前端结果:

[{"id":41,"username":"老王","address":"北京","sex":"男","birthday":"2018-02-27T17:47:08.000+0000","accounts":[{"id":1,"uid":41,"money":1000.0,"user":null},{"id":3,"uid":41,"money":3000.0,"user":null}]},{"id":42,"username":"小二王","address":"北京金燕龙","sex":"女","birthday":"2018-03-02T15:09:37.000+0000","accounts":[]},{"id":43,"username":"小二九","address":"北京金燕龙","sex":"女","birthday":"2018-03-04T11:34:34.000+0000","accounts":[{"id":2,"uid":43,"money":2000.0,"user":null}]},{"id":45,"username":"传智播客","address":"北京金燕龙","sex":"男","birthday":"2018-03-04T12:04:06.000+0000","accounts":[]},{"id":46,"username":"老久","address":"北京","sex":"女","birthday":"2018-03-07T17:37:26.000+0000","accounts":[]},{"id":48,"username":"小马宝莉","address":"北京修正","sex":"女","birthday":"2018-03-08T11:44:00.000+0000","accounts":[]},{"id":51,"username":"李四","address":"广西南宁市","sex":"男","birthday":"2019-07-21T06:29:22.000+0000","accounts":[]},{"id":52,"username":"王五","address":"广西桂林市","sex":"男","birthday":"2019-07-20T08:19:50.000+0000","accounts":[]}]
 


原文地址:https://www.cnblogs.com/hcklqy/p/11666936.html

时间: 2024-08-07 03:13:30

解决 mybatis 中相互关联的两种表数据在返回前端时一直循环查询,直到StackOverFlow报错的相关文章

MyBatis中id回填的两种方式

在一种场景下需要刚刚插入数据的ID,如果数据少可以先看数据库,记下ID,但数据很多,假设一万个用户并发,每个用户都插入自己的ID,就很难记下来. 下面给定一个场景: 1 User user = new User("张三","123456",new Date());//此时user没有id 2 userDao.insertUser(user); 3 sqlSession.commit();//此时数据已经插入到数据库中,数据库中有id,但user依然没有id 4 Sy

【新】mybatis中大于等于小于等于的两种常用写法

mybatis中大于等于小于等于的写法 原符号 < <= > >= & ' " 替换符号 < <= > >= & &apos; " 示例sql如下: create_date_time >= #{startTime} and create_date_time <= #{endTime} 第二种写法 大于等于 <![CDATA[ >= ]]> 小于等于 <![CDATA[ <=

在Word中去除超链接的两种方法

本文来自e良师益友网 不少朋友都有这样一个疑问:在Word中输入网站地址,回车之后,先前输入的地址就自动转变为了蓝色的超链接,如果我们不想这样,该如何设置呢?下面,简单的介绍两种方法给大家参考. 方法一:运用自动更正选项 1.启动Word2003,在空白处直接输入网站地址之后,自动变为蓝色的超链接形式,我们仔细发现,首字母下有一道横线,光标移动至此,显示自动更正选项. 2.单击自动更正选项,有三个可供选择的,选择控制自动更正选项. 3.在键入时自动套用格式选项卡中,取消勾选Internet及网络

MyBatis开发Dao层的两种方式(Mapper动态代理方式)

MyBatis开发原始Dao层请阅读我的上一篇博客:MyBatis开发Dao层的两种方式(原始Dao层开发) 接上一篇博客继续介绍MyBatis开发Dao层的第二种方式:Mapper动态代理方式 Mapper接口开发方法只需要程序员编写Mapper接口(相当于Dao接口),由Mybatis框架根据接口定义创建接口的动态代理对象,代理对象的方法体同上一篇博客中Dao接口实现类方法. Mapper接口开发需要遵循以下规范: (1)Mapper.xml文件中的namespace与mapper接口的类路

Java中Compareable和Comparator两种比较器的区别

Java中Compareable和Comparator两种比较器的区别 1.引言 在java这个处处是对象的世界里,对两个对象进行按某一属性进行比较是特别常见的需求.比如书店中的书按照价格比较,亦或者是学生按照成绩进行排名等等. 对于JDK8而言,有三种实现对象比较的方法: 1.在需要比较的对象类中覆写Object类的equals()方法: 2.需要比较的类继承Comparable接口,然后在其类内部实现compareTo()方法: 3.抛去需要被比较的类,在其外部自定义一个单独的对象比较器,继

使用库函数API和C代码中嵌入汇编代码两种方式使用同一个系统调用

使用库函数API和C代码中嵌入汇编代码两种方式使用同一个系统调用 选择调用的进程为 24 i386 getuid sys_getuid1647 i386 getgid sys_getgid16 使用库函数API方式 使用C代码中嵌入汇编代码方式

Linux中生成密钥的两种方法

Linux中生成密钥的两种方法 SSH服务支持一种安全认证机制,即密钥认证.所谓的密钥认证,实际上是使用一对加密字符串,一个称为公钥(publickey), 任何人都可以看到其内容,用于加密:另一个称为密钥(privatekey),只有拥有者才能看到,用于解密.通过公钥加密过的密文使用密钥可以轻松解密,但根据公钥来猜测密钥却十分困难. ssh的密钥认证就是使用了这一特性.服务器和客户端都各自拥有自己的公钥和密钥.如何使用密钥认证登录linux服务器呢? 在使用密钥认证远程登入linux之前,我们

实验--使用库函数API和C代码中嵌入汇编代码两种方式使用同一个系统调用(杨光)

使用库函数API和C代码中嵌入汇编代码两种方式使用同一个系统调用 攥写人:杨光  学号:20135233 ( *原创作品转载请注明出处*) ( 学习课程:<Linux内核分析>MOOC课程http://mooc.study.163.com/course/USTC-1000029000 实验要求: 选择一个系统调用(13号系统调用time除外),系统调用列表参见http://codelab.shiyanlou.com/xref/linux-3.18.6/arch/x86/syscalls/sys

java中设置代理的两种方式

1 前言 有时候我们的程序中要提供可以使用代理访问网络,代理的方式包括http.https.ftp.socks代理.比如在IE浏览器设置代理. 那我们在我们的java程序中使用代理呢,有如下两种方式.直接上代码. 2 采用设置系统属性 ? 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 import jav