Java中PageHelper关于Mybatis一对多关系折叠查询返回Total错误

Java中PageHelper关于Mybatis一对多关系折叠查询返回Total错误

遇到的问题

刚开始写Java,遇到分页问题,所以使用了PageHelper来进行分页,但是最近遇到 查询得到的列表和PageHelper返回的总数量对不上,究其原因是因为Mybatis中的一对多查询映射问题造成的。

解决方案

数据库

演示的小demo涉及两张表,一张是Person表,记录用户基本信息,另一张是phone表,记录电话号码,Person的phoneID外键关联phone表id。此处示例涉及并不符合实际情况,一对多方式是一个号码有多个用户使用的(更符合实际情况的是一个用户有多个号码),原因是从一对一demo直接扒拉过来用的,见谅,不过也能体现mybatis关联查询一对多的细节了。

Mybatis中一对多关系查询可以分两种方式查询

  1. 一种方式是先查询主表,获取到主表id,再通过主表id从子关联表中查询子信息列表,这种方式要和数据库交互两次,发出两次SQL语句,但是数据库返回的数据没有冗余;
  2. 另一种方式是直接关联查询,只与数据库交互一次,只发出一次SQL语句,但是数据库返回数据存在主表信息冗余,冗余数据为主表内容,冗余次数为从表中满足条件的记录数。

应该选择哪一种方式更合理,需要根据具体的业务场景来选择,没有绝对的正确,只有相对的适合。

  1. 第一种方式
    此种方式需要查询数据库两次,发出两次SQL语句,一次是查询tbl_phone表,一次是查询tbl_person表,但是数据库返回的信息没有冗余,mapper.xml配置和测试代码如下。
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper
  PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
  "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="cn.wxy.dao.PersonDao">
	<resultMap type="Phone" id="selectPhomap">
		<id property="id" column="id"/>
		<result property="phoneNum" column="phoneNum"/>
		<collection property="persons" ofType="Person" select="selectPer" column="id">
			<id property="id" column="id"/>
			<result property="username" column="username"/>
			<result property="password" column="password"/>
			<result property="gender" column="gender"/>
			<result property="age" column="age"/>
			<result property="phoneID" column="phoneID"/>
		</collection>
	</resultMap>
	<select id="select" parameterType="int" resultMap="selectPhomap">
		select * from tbl_phone where id=#{id}
	</select>
	<select id="selectPer" parameterType="int" resultType="Person">
		select * from tbl_person where phoneID=#{phoneID}
	</select>
</mapper>

在调用mapper接口中的select方法,先走语句“select * from tbl_phone where id=#{id}”,从数据库中拿到返回数据之后,开始做返回值映射,此时的返回值映射对象是一个resultMap(id:selectPhomap),该resultMap实际上是一个Phone实例,因此在开始做映射的时候,id和phoenNum因为属性名和数据库返回值一致完成映射,但是到了persons属性的时候,发现他是一个collection集合对象,里面存放的是Person实例,那怎么获取里面的数据?看collection标签的属性,他需要关联一个查询操作select="selectPer"获取其数据,

即通过select from tbl_person where phoneID=#{phoneID}获取collection中的数据,select="selectPer"操作需要传入数据,传入的数据column="id"即是第一次查询中返回的phone id,这个在这里显得不明显,在第二种方式中会更加的明显,这里也是mybatis关联查询的核心点,最后一步,就是将第二次查询出来的数据映射到collection中。详细过程,通过打印日志也可窥见一斑。

总结:

    1. 将查询操作拆成两步来完成;

    2. 核心点:第二次查询操作传入的数据通过collection的属性column来传入,此时column的value需要和第一次查询中的返回值做映射,映射的规则是数据库返回值的name和属性name相等;
  1. 第二种方式
    此种方式只需要查询数据库一次,发出一次sql语句,但是数据库返回值存在冗余,冗余内容为phone的信息,冗余次数是Person中使用统一电话的人的个数。mapper.xml配置文件内容如下。
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper
  PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
  "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="cn.wxy.dao.PersonDao">
	<resultMap type="Phone" id="selectPhomap">
		<id property="id" column="phoID"/>
		<result property="phoneNum" column="phoneNum"/>
		<collection property="persons" ofType="Person">
			<id property="id" column="id"/>
			<result property="username" column="username"/>
			<result property="password" column="password"/>
			<result property="gender" column="gender"/>
			<result property="age" column="age"/>
			<result property="phoneID" column="phoneID"/>
		</collection>
	</resultMap>
	<select id="select" parameterType="int" resultMap="selectPhomap">
		select pho.id phoID, pho.phoneNum, per.* from tbl_phone pho, tbl_person per
		where pho.id=#{id}
		and pho.id=per.phoneID
	</select>
</mapper>

通过此种方式实现关联查询,sql语句执行的返回值就已经包含了所有需要映射的数据,不需要再进行二次查询,但是存在一个问题,就是两张表的id字段的命名是一样的,所以在做关联查询的时候,需要将其中一个取别名以示区别,否则在映射的时候会出现不和实际情况的异常——sql和参数映射的时候是正确的,解析也是正确的,到数据库执行是正确的,数据库的返回值也是正确的,但是sql返回的是多条完整的数据记录,在做返回值映射的时候,因为phone和Person的主键都是id,一开始做映射的时候都被赋予值2,因为已经映射过了,所以第二条数据就不会在被映射。如以下所示的错误信息,person的信息其实是person.id=1的信息,但是其id=2,其他的信息都是id=1的数据。

总结:

1. 查询一步完成,关注sql的编写;

2. 注意sql返回之中是否存在同名的列,如果存在同名列,则mybatis做结果映射的时候有可能发生异常,需要取别名;

【注】:本文只为记录遇到的问题,非最终解决方案

  • 0
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值