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

Posted 水中游鱼

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了解决 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
@Repository
public 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":[]}]
 

 

以上是关于解决 mybatis 中相互关联的两种表数据在返回前端时一直循环查询,直到StackOverFlow报错的主要内容,如果未能解决你的问题,请参考以下文章

五 Mybatis一对一关联查询的两种方式(基于resultType&基于resultMap)

关于mybatis中的实体类属性与数据库中的列名不一致的两种解决方法

mybatis高级_数据库中的列和实体类不匹配时的两种解决方法_模糊查询_只能标签

Mybatis一对多查询的两种姿势,你值得拥有(收藏就完事了)

MyBatis注解开发的两种方法@Results和resultMap

mybatis一对多联表查询的两种常见方式