MyBatis分页
分页操作是为了减少数据的处理量,本节继续使用 MyBatis-04 项目研究一下怎么方便的实现分页。
1. Limit实现分页
在之前的 SMBMS 项目中,就是使用数据库的关键字 limit 实现的分页,接口和 SQL 语句如下
public interface UserMapper {
...
// 分页查询用户
public List<User> getUserByLimit(Map<String,Integer> map);
}
<!--在 UserMapper.xml 中-->
<select id="getUserByLimit" parameterType="map" resultMap="UserMap">
select * from mybatis.user limit #{startIndex},#{pageSize}
</select>
再写一个测试方法执行查询
public class UserMapperTest {
@Test
public void getUserByLimit(){
SqlSession sqlSession = MyBatisUtils.getSqlSession();
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
Map<String, Integer> map = new HashMap<String, Integer>();
// map 的 key 要和 SQL 中使用的名字相同!
map.put("startIndex",Integer.valueOf(0));
map.put("pageSize",Integer.valueOf(3));
List<User> userList = mapper.getUserByLimit(map);
for (User user : userList) {
System.out.println(user);
}
sqlSession.close();
}
}
查询的结果就是从数据库数据第0条( startIndex )记录开始的3条( pageSize )记录。
1.1 注意
在写代码的时候,我无意中将 #{ } 写为了 ${ },仍能执行正确的查询,但日志显示
[com.qiyuan.dao.UserMapper.getUserByLimit]-==> Preparing: select * from mybatis.user limit 0,3
[com.qiyuan.dao.UserMapper.getUserByLimit]-==> Parameters:
[com.qiyuan.dao.UserMapper.getUserByLimit]-<== Total: 3
即 SQL 语句没有了占位符 ?,直接就被补充了,参数 parameters 也为空。好奇之下发现了这个问题,正常的日志应为
[com.qiyuan.dao.UserMapper.getUserByLimit]-==> Preparing: select * from mybatis.user limit ?,?
[com.qiyuan.dao.UserMapper.getUserByLimit]-==> Parameters: 0(Integer), 3(Integer)
[com.qiyuan.dao.UserMapper.getUserByLimit]-<== Total: 3
看来日志还真好使,以后注意一下这个问题吧。
1.2 扩展
出于对 map 这个东西的好奇,我尝试将模糊查询和分页结合起来。模糊查询需要 name 参数,类型为 String,而分页的参数为 Integer 类型,我尝试用 Map<String, Object> map 把它们结合起来
修改方法中的参数类型和 SQL 语句
public interface UserMapper {
...
// 分页查询用户
public List<User> getUserByLimit(Map<String,Object> map);
}
<select id="getUserByLimit" parameterType="map" resultMap="UserMap">
select * from mybatis.user where name like #{name} limit #{startIndex},#{pageSize}
</select>
同时上面的测试方法中 map 的类型也要修改,再增加一个 key 为 name 的参数
public class UserMapperTest {
@Test
public void getUserByLimit(){
...
Map<String, Object> map = new HashMap<String, Object>();
map.put("name","%祈%");
map.put("startIndex",Integer.valueOf(0));
map.put("pageSize",Integer.valueOf(3));
...
}
}
执行结果
[com.qiyuan.dao.UserMapper.getUserByLimit]-==> Preparing: select * from mybatis.user where name like ? limit ?,?
[com.qiyuan.dao.UserMapper.getUserByLimit]-==> Parameters: %祈%(String), 0(Integer), 3(Integer)
[com.qiyuan.dao.UserMapper.getUserByLimit]-<== Total: 3
User{id=1, name='祈鸢', password='123456'}
User{id=3, name='風栖祈鸢', password='07230723'}
User{id=5, name='祈鸢bbb', password='123123'}
可以看到并没有什么问题嗷,挺好的。
2. RowBounds实现分页
使用 limit 是在 SQL 层面完成分页,而这个使用 RowBounds 的方法是在 Java 代码层面完成分页。
添加接口方法和对应配置如下
public interface UserMapper {
...
// RowBounds分页 不用传页面的参数
public List<User> getUserByRowBounds();
}
<!--RowBounds分页-->
<select id="getUserByRowBounds" resultMap="UserMap">
select * from mybatis.user
</select>
可以看到目前和直接查询所有用户没有区别,因为分页在 Java 代码中实现。
写一个测试方法实现
public class UserMapperTest {
@Test
public void getUserByRowBounds(){
SqlSession sqlSession = MyBatisUtils.getSqlSession();
// 从第1条记录开始取2条记录
RowBounds rowBounds = new RowBounds(1, 2);
// sqlSession实例化接口的第二种方式
List<User> userList = sqlSession.selectList("com.qiyuan.dao.getUserByRowBounds");
for (User user : userList) {
System.out.println(user);
}
sqlSession.close();
}
}
查询的结果
[com.qiyuan.dao.UserMapper.getUserByRowBounds]-==> Preparing: select * from mybatis.user
[com.qiyuan.dao.UserMapper.getUserByRowBounds]-==> Parameters:
User{id=2, name='Qiyuanc', password='123456'}
User{id=3, name='風栖祈鸢', password='07230723'}
可见这种方式也能实现分页,了解即可。
3. 总结
分页其实除了手写 limit 和 RowBounds 之外,也能使用分页插件。
如 MyBatis PageHelper 插件( https://pagehelper.github.io )就可以帮助分页。不过其底层实现也不过是 limit 和 RowBounds,只是封装的好而已。项目不大的时候还是要自己多写点东西