举个例子:
有两个实体类 User 和 Address
public class User {
private int id;
private String username; // 用户名
private List<Address> addresses;
// getter setter...
}
public class Address {
private int id;
private String detail; // 详细地址
private User user; //所属用户
// getter setter...
}
数据库:
create table t_user(
id int(10) primary key auto_increment,
username varchar(50)
);
create table t_address(
id int(10) primary key auto_increment,
detail varchar(255),
user_id int(10),
CONSTRAINT FOREIGN KEY (user_id) REFERENCES t_user(id)
);
mybatis映射配置:
<?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="org.mkh.shop.model.User">
<resultMap type="User" id="userMap" autoMapping="true">
<id property="id" column="u_id"/>
<collection property="address" ofType="Address">
<id property="id" column="a_id"/>
<result property="detail" column="detail"/>
</collection>
</resultMap>
<select id="find" resultType="User" parameterType="map">
select *,
ta.id as 'a_id',
tu.id as 'u_id'
from t_user tu
left join t_address ta on ta.user_id=tu.id
<where>
<if test="name != null">
(username like #{name})
</if>
</where>
<if test="sort != null">
order by ${sort}
<choose>
<when test="order != null">${order}</when>
<otherwise>asc</otherwise>
</choose>
</if>
limit #{pageOffset},#{pageSize}
</select>
<select id="find_count" resultType="int" parameterType="map">
select count(*)
from t_user tu
left join t_address ta on ta.user_id=tu.id
<where>
<if test="name != null">
(username like #{name})
</if>
</where>
</select>
</mapper>
用户和地址的关系为:一个用户有多个地址,一个地址只能属于一个用户,一对多
假设现在的需求是,分页查询用户,用表格显示,并把每个用户的所有地址显示出来
那么问题来了
按照上面的查询返回的分页的数据是没有问题的,但是分页的总记录数却是不对的。
比如查出来的数据(数据库数据,并非页面显示)如下:
u_id | username | a_id | detail |
---|---|---|---|
1 | user1 | 1 | 北京市海淀区 |
1 | user1 | 2 | 北京市朝阳区 |
2 | user2 | 3 | 天津市 |
因为我的需求是分页显示用户,所以一个用户就是一条数据在页面显示大概是这样子,理论上是两条数据,
用户id | 用户名 | 地址 |
---|---|---|
1 | user1 | 1. 北京市海淀区 2. 北京市朝阳区 |
2 | user2 | 1. 天津市 |
共1页,共2条数据,每页显示10条 |
但是,按mybatis的find_count配置 查出来是3条,这种问题如何解决?
查询count(*)的时候将所有left join 后面关联的表去除吗?这样会不会导致返回的数据不准确
补充说明:感觉大家是理解错我的意思了,其实我这个问题主要是在SQL 上,而不再mybatis上,因为我查询出来的数据映射完毕之后是完全没有问题的,只是在分页的总记录数上出现了问题,导致分页不正确
漂亮男人2017-06-10 09:51:39
刚才写了个例子测了一下
`
两个实体类
public class User {
private int id;
private String username; // 用户名
private List<Address> addresses;
public class Address {
private int id;
private String detail; // 详细地址
private int user_id; // 所属用户
映射文件
<resultMap type="com.atguigu.mybatis.entity.User" id="userMap" autoMapping="true">
<result property="id" column="u_id"/>
<collection property="addresses" ofType="com.atguigu.mybatis.entity.Address" autoMapping="true">
<result property="id" column="a_id"/>
<result property="user_id" column="u_id"/>
</collection>
</resultMap>
<select id="select_all_user_address" resultMap="userMap" >
<!-- select tu.,ta., -->
<!-- ta.id as 'a_id', -->
<!-- tu.id as 'u_id' -->
<!-- from t_user tu , -->
<!-- t_address ta where ta.user_id=tu.id -->
select tu.*,ta.*,
ta.id as 'a_id',
tu.id as 'u_id'
from t_user tu
left join t_address ta on ta.user_id=tu.id
</select>
测试结果
封装成的 List<User>的size是没问题的
欧阳克2017-06-10 09:51:39
SELECT
*, ta.id AS 'a_id', tu.id AS 'u_id'
FROM
t_user tu
LEFT JOIN
t_address ta ON ta.user_id = tu.id;
你希望想要两条 但是你的sql查出三条,所以显示错误,
应该拆分逻辑:
应该先查出你想要的用户
<select id="find" resultType="User" parameterType="map">
select *
from t_user tu
<where>
<if test="name != null">
(username like #{name})
</if>
</where>
<if test="sort != null">
order by ${sort}
<choose>
<when test="order != null">${order}</when>
<otherwise>asc</otherwise>
</choose>
</if>
limit #{pageOffset},#{pageSize}
</select>
然后在
<resultMap type="User" id="userMap" autoMapping="true">
<id property="id" column="u_id"/>
<collection " property="addresses" javaType= "ArrayList" column="u_id"
ofType="Address" select= "??" />
</resultMap>
??是自己实现个 用userId查List<Address>的方法
欧阳克2017-06-10 09:51:39
这种情况不能这么分页,你需要对主表数据进行分页。
本来查询出100条数据,由于一对多会折叠去重很多数据,导致实际结果少于100条。
这种情况下可以采取嵌套查询方式解决,就是需要N+1次执行,可以懒加载。
或者看这里:https://my.oschina.net/flags/...
有关 MyBatis 内容可以访问:http://mybatis.tk
扔个三星炸死你2017-06-10 09:51:39
<select id="find_count" resultType="int" parameterType="map">
select count(*)
from t_user tu
left join t_address ta on ta.user_id=tu.id
<where>
<if test="name != null">
(username like #{name})
</if>
</where>
</select>
改:
<select id="find_count" resultType="int" parameterType="map">
select count(*)
from t_user tu
<where>
<if test="name != null">
(username like #{name})
</if>
</where>
group by username
</select>
曾经蜡笔没有小新2017-06-10 09:51:39
用子查询就不会有问题了
select count(*) from (
// query 在这里即使关联100张表, 也不可能存在问题
)
楼主可以看一下Mybatis-PageHelper
count sql 转换实现
建议楼主直接使用 Mybatis-PageHelper 实现分页