在此之前请参考文章:
1、Spring Boot整合Mybatis框架在扩展文件编写自己的sql语句
2、Mybatis单表分页查询
有两张数据库表user和user_info,他们是一对一关系,user_info以user_id关联user表的id
CREATE TABLE `user` (
`id` int(11) NOT NULL AUTO_INCREMENT COMMENT '主键',
`username` varchar(20) DEFAULT NULL COMMENT '用户名',
`password` varchar(100) DEFAULT NULL COMMENT '密码',
`age` int(3) DEFAULT NULL COMMENT '年龄',
`sex` varchar(1) DEFAULT NULL COMMENT '性别',
`add_time` datetime DEFAULT NULL COMMENT '添加时间',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8;
CREATE TABLE `user_info` (
`id` int(11) NOT NULL,
`user_id` int(11) NOT NULL COMMENT '用户id,关联user表',
`phone` varchar(20) DEFAULT NULL COMMENT '手机号',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
以user_info为主表关联user表进行查询的语句如下:
SELECT
*
FROM
user_info uf
LEFT JOIN `user` u ON u.id = uf.user_id
WHERE
1 = 1
AND u.sex = '男'
下文将介绍两种方式实现该语句的分页查询功能。
首先编写dao层相关代码
UserInfoMapperExt.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="com.beibei.doc.dao.user.ext.UserInfoMapperExt" >
<resultMap id="ExtResultMap" extends="com.beibei.doc.dao.user.UserInfoMapper.BaseResultMap" type="com.beibei.doc.model.user.UserInfo" >
</resultMap>
<!-- 排序和分页参数 -->
<sql id="sort_limit">
<if test="orderBy != null">
order by ${orderBy}
</if>
<if test="limit != null">
limit ${start} , ${limit}
</if>
</sql>
<!-- 需要查询的字段 -->
<sql id="UserInfo_Column_List" >
*
</sql>
<!-- 查询的表及查询条件设置 -->
<sql id="UserInfo_From_Where" >
FROM
user_info uf
LEFT JOIN `user` u ON u.id = uf.user_id
WHERE
1 = 1
<if test="map.sex != null">
AND u.sex = '${map.sex}'
</if>
</sql>
<!-- 用户信息分页查询 -->
<select id="selectUserInfoListPage" resultType="java.util.Map" parameterType="com.beibei.doc.util.Page">
SELECT
<include refid="UserInfo_Column_List"></include>
<include refid="UserInfo_From_Where"></include>
<include refid="sort_limit"></include>
</select>
<!-- 用户信息数量查询 -->
<select id="selectUserInfoListPageTotal" resultType="java.lang.Integer" parameterType="com.beibei.doc.util.Page">
SELECT
count(*)
<include refid="UserInfo_From_Where"></include>
</select>
</mapper>
UserInfoMapperExt.java文件
package com.beibei.doc.dao.user.ext;
import com.beibei.doc.dao.base.BaseMapperExt;
import com.beibei.doc.model.user.UserInfo;
import com.beibei.doc.model.user.UserInfoExample;
import com.beibei.doc.util.Page;
public interface UserInfoMapperExt extends BaseMapperExt<UserInfo, UserInfoExample> {
}
注意:
1、其中UserInfoMapperExt.xml文件有两个select,id分别是selectUserInfoListPage、selectUserInfoListPageTotal,前者是带条件联表查询数据的sql语句,后者是和前者完全一样的条件查询数量的语句,其名称一定要遵循前者名称+Total的方式命名。
parameterType一定要设置为类com.beibei.doc.util.Page,这个类源码请去看文章
Mybatis单表分页查询(http://www.jianshu.com/p/67b3bfab7da3)
2、UserInfoMapperExt.java文件继承BaseMapperExt.java。
有了dao层,就可以分别用两种方式实现联表分页查询了。
方式一:
1、在UserInfoMapperExt.java文件中定义两个方法,与UserInfoMapperExt.xml文件中的selectUserInfoListPage、selectUserInfoListPageTotal一一对应,这样子就可以通过这两个方法直接执行这两个sql语句了。
需要注意的是方法的返回值要与sql语句中定义的resultType相对应,如resultType="java.util.Map"对应的是List<Map<String, Object>>,因为selectUserInfoListPage查询返回值是多条数据,所以是一个list。
至于list的泛型可以是map,也可以是任意定义的一个类,这个类中的字段要与sql查询结果集的字段对应,如果存在查询结果中没有的字段,需要在其getter方法上加注释@Transient,查询结果集中有,类中没有的字段则无影响。
里面引用的的Page.java类请参考文章
Mybatis单表分页查询 http://www.jianshu.com/p/67b3bfab7da3
/**
* 用户信息分页查询
* @param page
* @return
*/
public List<Map<String, Object>> selectUserInfoListPage(Page<UserInfo, UserInfoExample> page);
/**
* 用户信息数量查询
* @param page
* @return
*/
public Integer selectUserInfoListPageTotal(Page<UserInfo, UserInfoExample> page);
2、service层代码编写
创建UserInfoService.java,继承基类接口类BaseService.java
package com.beibei.doc.service.user;
import java.util.Map;
import com.beibei.doc.model.user.UserInfo;
import com.beibei.doc.model.user.UserInfoExample;
import com.beibei.doc.service.base.BaseService;
import com.beibei.doc.util.RespData;
public interface UserInfoService extends BaseService<UserInfo, UserInfoExample> {
public RespData selectUserInfoListPage(Map<String, Object> param);
}
创建其实现类UserInfoServiceImpl.java,在里面实现分页查询方法selectUserInfoListPage,
package com.beibei.doc.service.user.impl;
import java.util.List;
import java.util.Map;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.beibei.doc.dao.user.ext.UserInfoMapperExt;
import com.beibei.doc.model.user.UserInfo;
import com.beibei.doc.model.user.UserInfoExample;
import com.beibei.doc.service.base.impl.BaseServiceImpl;
import com.beibei.doc.service.user.UserInfoService;
import com.beibei.doc.util.Page;
import com.beibei.doc.util.RespData;
@Service
public class UserInfoServiceImpl extends BaseServiceImpl<UserInfo, UserInfoExample> implements UserInfoService {
@Autowired
private UserInfoMapperExt userInfoMapperExt;
@Override
public RespData selectUserInfoListPage(Map<String, Object> param) {
RespData data = new RespData();
Page<UserInfo, UserInfoExample> page = new Page<>(param);
page.setMap(param);
Integer total = userInfoMapperExt.selectUserInfoListPageTotal(page);
page.setTotal(total);
List<Map<String, Object>> list = userInfoMapperExt.selectUserInfoListPage(page);
page.setList(list);
data.setData(page.getPageData());
return data;
}
}
到这里分页功能就实现了,在调用该方法时候参数param中要有 下一页页码nextPage 和 每页数量limit 两个key的值,如果需要性别过滤,把sex的key值也放入param对象,然后调用page.setMap(param);来设置参数,可以仔细研究UserInfoMapperExt.xml文件中的代码片段
<!-- 查询的表及查询条件设置 -->
<sql id="UserInfo_From_Where" >
FROM
user_info uf
LEFT JOIN `user` u ON u.id = uf.user_id
WHERE
1 = 1
<if test="map.sex != null">
AND u.sex = '${map.sex}'
</if>
</sql>
方式二:
我的项目是和Spring Boot整合起来的,请先参考文章
Spring Boot一步步整合Mybatis框架(http://www.jianshu.com/p/04aaa872ba30)
1、在配置类DataBaseConfig.java中加入SqlSessionTemplate的bean声明
@Bean
public SqlSessionTemplate sqlSessionTemplate(){
return new SqlSessionTemplate(this.sqlSessionFactory());
}
如果是配置文件的应该是这样子吧。
<bean id="sqlSessionTemplate" class="org.mybatis.spring.SqlSessionTemplate">
<constructor-arg ref="sqlSessionFactory" />
</bean>
2、在BaseService.java中定义方法
/**
* <pre>
* 关联表分页查询接口
* 说明:该方式查询实际上是通过sqlSessionTemplate对象来
* 调用在 MapperExt.xml 文件中定义的查询sql语句, 因此要指定调用的select的id
* 以及该select所在的MapperExt.xml文件所对应的接口类(该类全名称作为该MapperExt.xmll文件的命名空间),
* 务必保证能够正确拼接出完整的引用路径。
* 比如一个联表查询的sql: com.beibei.doc.dao.user.ext.UserInfoMapperExt.selectUserInfoListPage
* 传入参数是 selectId="selectUserInfoListPage", clazz=UserInfoMapperExt.class
* </pre>
* @param selectId 扩展文件MapperExt.xml中定义的查询语句id
* @param page 分页对象
* @param clazz 对应的MapperExt接口类
* @return
*/
public Page<M, E> selectByParamListPage(String selectId, Page<M, E> page, Class<? extends BaseMapperExt<M, E>> clazz);
在BaseServiceImpl.java中实现上面定义的方法,并且添加自动注入的SqlSessionTemplate对象属性
@Autowired
private SqlSessionTemplate sqlSessionTemplate;
@Override
public Page<M, E> selectByParamListPage(String selectId, Page<M, E> page, Class<? extends BaseMapperExt<M, E>> clazz) {
String ext = clazz.toString().replace("interface ", "");
Integer total = sqlSessionTemplate.selectOne(ext + "." + selectId + "Total", page);
page.setTotal(total);
List<?> list = sqlSessionTemplate.selectList(ext + "." + selectId, page);
page.setList(list);
return page;
}
3、调用该方法
Page<UserInfo, UserInfoExample> page = new Page<>(param);
page = userInfoService.selectByParamListPage("selectUserInfoListPage", page, UserInfoMapperExt.class);
data.setData(page.getPageData());//获取分页查询结果
总结
对比上面两种方式可以发现方式一要在MapperExt.xml中定义和select的id相同的方法,比较麻烦。方式二则可以直接用select的id来调用BaseService中的selectByParamListPage方法就可以了,比较方便简洁。