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());
        }
    }
}

 

posted @ 2018-09-13 10:30  无天666  阅读(8858)  评论(0编辑  收藏  举报