假设有如下实体表USER和USER_GROUP,及其映射表USER_MAPPING_USER_GROUP
ID | USER_ACCOUNT | USER_NAME |
1 | zhangsan | 张三 |
ID | USER_GROUP_NAME |
1 | 管理员组 |
USER_ID | USER_GROUP_ID |
1 | 1 |
现在要根据传入的查询参数:USER_ACCONT和USER_GROUP_NAME 对 USER表进行分页查询,在MyBatis中使用resultMap中的collection实现一对多查询时查询返回的记录数量和总数量会出现不符合实际情况的问题,如下的sql代码所示,原因在于主表USER left join映射表USER_MAPPING_USR_GROUP和从表USER_GROUP时,返回的记录中包含主表字段(USER_ACCOUNT等)和从表字段(USER_GROUP_NAME等),自然而然就多于只查询主表返回的记录数量了。
<!--mybatis+oracle-->
<select id="selectUserGroupInfoByCondition" parameterType="string" resultMap="UserGroupMap">
select uu.*, ug.ID USER_GROUP_ID, ug.USER_GROUP_NAME from (
select
u.ID,UPPER(u.USER_NAME) as USER_NAME,UPPER(u.USER_ACCOUNT) as
USER_ACCOUNT
from "USER" u
WHERE 1=1
<if test="param.userAccount != null and param.userAccount !=''">
AND UPPER(u.USER_ACCOUNT) LIKE UPPER(CONCAT(CONCAT('%',#{param.userAccount,jdbcType=VARCHAR}),'%'))
</if>
) uu
left join ${module}."USER_MAPPING_USER_GROUP" umug on uu.ID = umug.USER_ID
left join ${module}."USER_GROUP" ug on umug.USER_GROUP_ID = ug.ID
where 1=1
<if test="param.userGroupName != null and param.userGroupName !=''">
AND UPPER(ug.USER_GROUP_NAME) = #{param.userGroupName,jdbcType=VARCHAR}
and ug.IS_DELETE = 'N'
</if>
ORDER BY uu.ID
</select>
<resultMap type="com.portal.entity.User" id="UserGroupMap">
<!-- 配置用户主键 -->
<id column="ID" property="id" jdbcType="DECIMAL"/>
<!-- 配置普通属性 -->
<result column="USER_NAME" property="userName" jdbcType="VARCHAR"/>
<result column="USER_ACCOUNT" property="userAccount"/>
<collection property="userGroups" ofType="com.xxx.xxx.UserGroup" javaType="list">
<id column="USER_GROUP_ID" property="id"/> <!--主键字段,oracle中的 number类型 对应 DECIMAL-->
<result column="USER_GROUP_NAME" property="userGroupName"/> <!-- oracle中的 varchar2类型 对应 VARCHAR -->
</collection>
</resultMap>
如何解决该问题,pagehelper已经提示不支持上面这种情况的查询了。https://github.com/pagehelper/Mybatis-PageHelper/blob/master/wikis/zh/Important.md
解决该问题的思路很直接,手写分页逻辑就可以了,因为非常简单。
于是上面的sql查询语句就变为下面的。
<select id="selectUserGroupInfoByCondition" parameterType="string" resultMap="UserGroupMap">
SELECT pagea.*, ug.USER_GROUP_NAME,ug.ID USER_GROUP_ID FROM
(SELECT * FROM (select pageb.*, ROWNUM ROW_ID from (
select distinct uu.ID,uu.USER_NAME,uu.USER_ACCOUNT
from
(
select
u.ID,UPPER(u.USER_NAME) as USER_NAME,UPPER(u.USER_ACCOUNT) as
USER_ACCOUNT
from "USER" u
WHERE 1=1
<if test="param.userAccount != null and param.userAccount !=''">
AND UPPER(u.USER_ACCOUNT) LIKE UPPER(CONCAT(CONCAT('%',#{param.userAccount,jdbcType=VARCHAR}),'%'))
</if>
) uu
left join "USER_MAPPING_USER_GROUP" umug on uu.ID = umug.USER_ID
left join "USER_GROUP" ug on umug.USER_GROUP_ID = ug.ID
where 1=1
<if test="param.userGroupName != null and param.userGroupName !=''">
AND UPPER(ug.USER_GROUP_NAME) = #{param.userGroupName,jdbcType=VARCHAR}
</if>
ORDER BY uu.ID ) pageb WHERE ROWNUM < ${param.pageSize} + ${param.currentPage})
WHERE ROW_ID >= #{param.currentPage,jdbcType=DECIMAL} ) pagea
left join "USER_MAPPING_USER_GROUP" umug on pagea.ID = umug.USER_ID
left join "USER_GROUP" ug on umug.USER_GROUP_ID = ug.ID
</select>
<!--查询总数量-->
<select id="countUserGroupINfoByCondition" parameterType="string" resultType="java.lang.Long">
select count (distinct uu.ID)
from
(
select
u.ID,UPPER(u.USER_NAME) as USER_NAME,UPPER(u.USER_ACCOUNT) as
USER_ACCOUNT
from "USER" u
WHERE 1=1
<if test="param.userAccount != null and param.userAccount !=''">
AND UPPER(u.USER_ACCOUNT) LIKE UPPER(CONCAT(CONCAT('%',#{param.userAccount,jdbcType=VARCHAR}),'%'))
</if>
) uu
left join "USER_MAPPING_USER_GROUP" umug on uu.ID = umug.USER_ID
left join "USER_GROUP" ug on umug.USER_GROUP_ID = ug.ID
where 1=1
<if test="param.userGroupName != null and param.userGroupName !=''">
AND UPPER(ug.USER_GROUP_NAME) = #{param.userGroupName,jdbcType=VARCHAR}
</if>
ORDER BY uu.ID
</select>