分页操作是为了减少数据的处理量,本节继续使用 MyBatis-04 项目研究一下怎么方便的实现分页。
在之前的 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 )记录。
在写代码的时候,我无意中将 #{ } 写为了 ${ },仍能执行正确的查询,但日志显示
[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
看来日志还真好使,以后注意一下这个问题吧。
出于对 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'}
可以看到并没有什么问题嗷,挺好的。
使用 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'}
可见这种方式也能实现分页,了解即可。
分页其实除了手写 limit 和 RowBounds 之外,也能使用分页插件。
如 MyBatis PageHelper 插件( https://pagehelper.github.io )就可以帮助分页。不过其底层实现也不过是 limit 和 RowBounds,只是封装的好而已。项目不大的时候还是要自己多写点东西