Mybatis+MySQL动态分页查询
https://blog.csdn.net/qq_34137397/article/details/63289621
mybatis有两种分页方法
1、内存分页,也就是假分页。本质是查出所有的数据然后根据游标的方式,截取需要的记录。如果数据量大,开销大和内存溢出。
第二中是,真正的物理分页
还有一种是使用分页拦截器实现的
常见的数据分页有哪几种实现??基于数组的分页实现?基于sql语句的分页实现?还是通过拦截器进行数据分页功能?还是通过RowBounds参数进行物理分页?几种都是常用的分页实现原理
一.借助数组进行分页
原理:进行数据库查询操作时,获取到数据库中所有满足条件的记录,保存在应用的临时数组中,再通过List的subList方法,获取到满足条件的所有记录。
二.借助Sql语句进行分页,物理分页
实现:通过sql语句实现分页也是非常简单的,只是需要改变我们查询的语句就能实现了,即在sql语句后面添加limit分页语句。 首先还是在StudentMapper接口中添加sql语句查询的方法,如下: List<Student> queryStudentsBySql(Map<String,Object> data); 然后在StudentMapper.xml文件中编写sql语句通过limiy关键字进行分页: <select id="queryStudentsBySql" parameterType="map" resultMap="studentmapper"> select * from student limit #{currIndex} , #{pageSize} </select> 接下来还是在IStuService接口中定义方法,并且在StuServiceIml中对sql分页实现。 List<Student> queryStudentsBySql(int currPage, int pageSize); @Override public List<Student> queryStudentsBySql(int currPage, int pageSize) { Map<String, Object> data = new HashedMap(); data.put("currIndex", (currPage-1)*pageSize); data.put("pageSize", pageSize); return studentMapper.queryStudentsBySql(data); } sql分页语句如下:select * from table limit index, pageSize;
四.RowBounds实现分页 原理:通过RowBounds实现分页和通过数组方式分页原理差不多,都是一次获取所有符合条件的数据,然后在内存中对大数据进行操作,实现分页效果。只是数组分页需要我们自己去实现分页逻辑,这里更加简化而已。 存在问题:一次性从数据库获取的数据可能会很多,对内存的消耗很大,可能导师性能变差,甚至引发内存溢出。 适用场景:在数据量很大的情况下,建议还是适用拦截器实现分页效果。RowBounds建议在数据量相对较小的情况下使用。 简单介绍:这是代码实现上最简单的一种分页方式,只需要在dao层接口中要实现分页的方法中加入RowBounds参数,然后在service层通过offset(从第几行开始读取数据,默认值为0)和limit(要显示的记录条数,默认为java允许的最大整数:2147483647)两个参数构建出RowBounds对象,在调用dao层方法的时,将构造好的RowBounds传进去就能轻松实现分页效果了。 具体操作如下: dao层接口方法: //加入RowBounds参数 public List<UserBean> queryUsersByPage(String userName, RowBounds rowBounds); 然后在service层构建RowBounds,调用dao层方法: @Override @Transactional(isolation = Isolation.READ_COMMITTED, propagation = Propagation.SUPPORTS) public List<RoleBean> queryRolesByPage(String roleName, int start, int limit) { return roleDao.queryRolesByPage(roleName, new RowBounds(start, limit)); } RowBounds就是一个封装了offset和limit简单类,如下所示: public class RowBounds { public static final int NO_ROW_OFFSET = 0; public static final int NO_ROW_LIMIT = 2147483647; public static final RowBounds DEFAULT = new RowBounds(); private int offset; private int limit; public RowBounds() { this.offset = 0; this.limit = 2147483647; } public RowBounds(int offset, int limit) { this.offset = offset; this.limit = limit; } public int getOffset() { return this.offset; } public int getLimit() { return this.limit; } } 只需要这两步操作,就能轻松实现分页效果了,是不是很神奇。但却不简单,内部是怎么实现的??给大家提供一个简单的思路:RowBounds分页简单原理 结论:从上面四种sql分页的实现方式可以看出,通过RowBounds实现是最简便的,但是通过拦截器的实现方式是最优的方案。只需一次编写,所有的分页方法共同使用,还可以避免多次配置时的出错机率,需要修改时也只需要修改这一个文件,一劳永逸。而且是我们自己实现的,便于我们去控制和增加一些逻辑处理,使我们在外层更简单的使用。同时也不会出现数组分页和RowBounds分页导致的性能问题。当然,具体情况可以采取不同的解决方案。数据量小时,RowBounds不失为一种好办法。但是数据量大时,实现拦截器就很有必要了。 到这里,mybatis的分页原理和全部实现过程都完成了,还有不清楚的可以自己去看一下mybatis的源码,按照这个思路去阅读还是比较清晰的。这里只是对插件(拦截器)实现分页做了个简单的介绍,只是简单的分页功能,还很简陋。在下一遍博客我们将会实现一个封装好的、功能齐全的实用性插件。传送门:mybatis精通之路之插件分页(拦截器)进阶 最后,希望大家提出宝贵意见,共同学习。
1. 使用Map来进行包装数据实现分页功能 1),在SQL语句映射的ResultType返回的是你要查询得到的实体类 2),穿进去的参数parameterType是你自己包装的Map类型 3),首先你传进来的参数要和SQL语句中的字段名要保持一致 4),在实体DAO层还需要把查询数据的起始下标,和查询多少条数据都put进Map中 SQL映射: <!--查询所有的用户信息,用map分页实现--> <select id="getAllMap" resultType="User" parameterType="Map"> SELECT * FROM user limit #{startIndex},#{pageSize} </select> DAO实现类 //这个是实现分页查询功能(用map来实现的第一种方式) public List<User> getAll(int currentPage,int pageSize) throws IOException { SqlSession sqlSession = MybatisUtil.getSession(); Map<String,Integer> map = new HashMap<String, Integer>(); //这个是把当 map.put("startIndex",(currentPage-1)*pageSize); map.put("pageSize",pageSize); List<User> list = sqlSession.selectList("UserMapper.getAllMap",map); sqlSession.close(); return list; } 测试类 public static void main(String[] args) throws IOException { UserDao userDao = new UserDao(); //这个传进来的第一个参数是你要显示第几页的数据,第二是你需要没页显示几条记录 List<User> list = userDao.getAll(2, 3); for (User user : list) { System.out.println(user.toString()); } }
2. 使用RowBounds来实现分页 1),只需要设置一个返回值为User实体类型 2),RowBounds rowBounds= newRowBounds((currentPage-1)*pageSize,pageSize); 3),就是上一步多了一个创建一个RowBounds对象,然后需要传入SQL语句中需要的参数就行了 4),然后sqlSession在执行selectList的时候把那个rowBounds对象直接传进去就可以了 SQL的xml映射 <!--查询所有用户的信息,用RowBounds来实现--> <select id="getAllRowBounds" resultType="User"> SELECT *FROM user </select> DAO实现类 //这个是通过RowBounds来实现查询功能的分页操作 public List<User> getAllRowBounds(int currentPage,int pageSize) throws IOException { SqlSession sqlSession = MybatisUtil.getSession(); /*rowBounds需要的第一个参数就是从数据的哪个下标开始开始查,第二个就是你需要查询的条数*/ RowBounds rowBounds= new RowBounds((currentPage-1)*pageSize,pageSize); List<User> list = sqlSession.selectList("UserMapper.getAllRowBounds", null, rowBounds); sqlSession.close(); return list; } 测试类 ublic class TestRowBounds { public static void main(String[] args) throws IOException { UserDao userDao = new UserDao(); List<User> list = userDao.getAllRowBounds(1, 3); for (User user : list) { System.out.println(user.toString()); } } }