当前位置: 代码网 > it编程>编程语言>Java > MyBatis实现分页的两种方式

MyBatis实现分页的两种方式

2025年07月04日 Java 我要评论
在 mybatis 中实现分页通常有两种方式:使用数据库厂商提供的分页查询语句(如 mysql 的 limit)或者通过自定义 sql 来实现分页逻辑等mybatis分页方式对比mybatis提供了多

在 mybatis 中实现分页通常有两种方式:使用数据库厂商提供的分页查询语句(如 mysql 的 limit)或者通过自定义 sql 来实现分页逻辑等

mybatis分页方式对比

mybatis提供了多种分页方式,每种方式都有其特定的应用场景和优缺点。以下是对mybatis中几种常见分页方式的对比:

  1. 基于rowbounds的分页(逻辑分页):
    ○ 原理:执行完整的sql查询,将结果集全部加载到内存中,然后根据rowbounds指定的偏移量和限制数进行分页处理。
    ○ 优点:减少io次数,对于频繁访问且数据量较小的情况较为适合。
    ○ 缺点:当数据量非常大时,容易造成内存溢出,性能下降。
  2. 基于数据库的分页(物理分页):
    ○ 原理:在sql查询语句中使用limit和offset关键字来实现分页,直接在数据库层面进行分页处理。
    ○ 优点:适用于大数据量的情况,避免了内存溢出的风险,性能较好。
    ○ 缺点:需要数据库支持limit和offset语法,不同数据库厂商的语法可能有所不同。
  3. 基于插件的分页:
    ○ 原理:mybatis提供了插件机制,通过自定义插件来拦截sql语句的执行,并在查询结果返回之前添加分页逻辑。
    ○ 优点:插件封装了分页的具体实现细节,使用起来简单方便,适用于多种分页需求。
    ○ 缺点:可能需要一定的开发成本来编写和维护插件。
  4. 数组分页:
    ○ 原理:首先查询出全部数据,然后在java代码的list中截取需要的部分。
    ○ 优点:实现简单。
    ○ 缺点:当数据量很大时,会消耗大量内存,并可能导致性能问题。
    综上所述,选择哪种分页方式取决于具体的应用场景和数据量大小。对于小数据量或频繁访问的场景,逻辑分页(如rowbounds)可能是一个不错的选择。而对于大数据量或需要高效分页的场景,物理分页(如基于数据库的分页)或基于插件的分页可能更为合适。在实际应用中,还需要考虑数据库类型、系统性能、开发成本等因素来做出决策。

使用数据库厂商提供的分页查询语句

许多数据库厂商都提供了用于分页的特定语法,如 mysql 的 limit、oracle 的 rownum、sql server 的 offset fetch 等。你可以直接在 sql 查询语句中使用这些语法来实现分页,然后将分页参数传递给 mybatis 的方法即可。
示例(mysql):

<select id="getuserlist" resulttype="user">
    select * from users
    limit #{offset}, #{pagesize}
</select>
list<user> getuserlist(@param("offset") int offset, @param("pagesize") int pagesize);

通过自定义 sql 实现分页逻辑

如果你使用的数据库不支持特定的分页语法,或者想要更多灵活性,你可以通过自定义 sql 实现分页逻辑。通常,你需要通过 rowbounds 或 pagehelper 来实现分页。

1. 使用 rowbounds 实现分页

原理:通过rowbounds实现分页和通过数组方式分页原理差不多,都是一次获取所有符合条件的数据,然后在内存中对大数据进行操作,实现分页效果。只是数组分页需要我们自己去实现分页逻辑,这里更加简化而已。
存在问题:一次性从数据库获取的数据可能会很多,对内存的消耗很大,可能导师性能变差,甚至引发内存溢出。
适用场景:在数据量很大的情况下,建议还是适用拦截器实现分页效果。rowbounds建议在数据量相对较小的情况下使用。
rowbounds分页是mybatis提供的一种分页方式,其原理主要是在执行sql查询后,将返回的所有结果集加载到内存中,然后在内存中根据指定的偏移量(offset)和限制数(limit)进行分页处理。
具体来说,当我们在mybatis的mapper接口中调用查询方法时,可以传入一个rowbounds对象作为参数。这个rowbounds对象包含了分页所需的信息,比如当前页码、每页显示的记录数等。在执行查询时,mybatis会首先执行完整的sql查询语句,获取到所有满足条件的结果集。然后,mybatis会根据rowbounds对象中指定的偏移量和限制数,在内存中对这些结果集进行截取,从而得到当前页需要展示的数据。
需要注意的是,rowbounds分页方式是一种逻辑分页,即在内存中进行分页处理。当数据量非常大时,这种方式可能会导致内存溢出的问题。因此,对于大数据量的分页需求,建议使用物理分页方式,即在sql查询语句中添加limit和offset子句,直接在数据库层面进行分页处理。
此外,mybatis还提供了另一种分页插件pagehelper,它使用拦截器的方式实现了物理分页。pagehelper插件会在mybatis执行sql查询之前,自动根据传入的分页参数改写sql语句,添加limit和offset子句,从而实现物理分页。这种方式可以更有效地处理大数据量的分页需求,避免内存溢出的问题。
list getuserlist(rowbounds rowbounds);
rowbounds rowbounds = new rowbounds(offset, pagesize);
list users = sqlsession.selectlist(“getuserlist”, rowbounds);

2. 使用 pagehelper 实现分页

pagehelper的分页原理主要基于mybatis的插件机制。具体来说,pagehelper内部实现了一个pageinterceptor拦截器,这个拦截器会在mybatis执行sql查询之前进行拦截。
当我们在代码中调用pagehelper的startpage方法时,它会在当前线程上下文中设置一个threadlocal变量,用于保存分页的参数,如当前页码、每页显示的数量等。
随后,当mybatis执行sql查询时,pageinterceptor拦截器会拦截到这一操作。拦截器会从threadlocal中获取到分页参数,并根据这些参数来改写原始的sql语句,添加limit和offset子句,以实现分页查询。
改写后的sql语句会被发送到数据库执行,数据库返回的结果集就是根据分页参数查询得到的结果。
最后,pageinterceptor拦截器会将threadlocal中的分页参数清除,避免对后续操作产生影响。
通过这种方式,pagehelper实现了对mybatis查询结果的分页处理,而无需修改原有的sql语句、mapper接口和xml文件,因此具有无侵入性和易用性。同时,由于分页操作是在数据库层面进行的,因此也具有较高的性能。
需要注意的是,pagehelper使用了threadlocal来保存分页参数,因此分页参数是与线程绑定的,这意味着不同的线程之间不会共享分页参数,从而保证了分页的准确性和独立性。
总的来说,pagehelper通过拦截mybatis的sql查询操作,并在查询语句中添加limit和offset子句,实现了对查询结果的分页处理,从而简化了分页操作的实现过程,提高了开发效率。
pagehelper 是一个 mybatis 的分页插件,可以简化分页操作。
首先,在 mybatis 的配置文件中配置 pagehelper 插件:

<plugins>
    <plugin interceptor="com.github.pagehelper.pageinterceptor">
        <property name="helperdialect" value="mysql"/>
    </plugin>
</plugins>
然后,在需要分页的查询方法中添加分页参数:
list<user> getuserlist(@param("pagenum") int pagenum, @param("pagesize") int pagesize);
pagehelper.startpage(pagenum, pagesize);
list<user> users = usermapper.getuserlist(pagenum, pagesize);
这两种方式都可以实现分页查询,你可以根据实际需求选择合适的方式。

数组分页

使用数组进行分页通常意味着在数据库中获取所有数据,然后在应用程序中对数据进行分割和展示。这种方法在数据量较小且不频繁变化时比较适用,但在数据量较大时可能会影响性能。下面是一个简单的 java 代码示例,演示如何使用数组进行分页:

import java.util.arraylist;
import java.util.list;
public class paginationwitharrayexample {
    // 模拟从数据库中获取数据的方法,返回所有数据
    public list<string> fetchdatafromdatabase() {
        // 这里假设从数据库中获取了一些数据,实际情况根据需求修改
        list<string> datalist = new arraylist<>();
        for (int i = 1; i <= 100; i++) {
            datalist.add("data " + i);
        }
        return datalist;
    }
    // 根据页码和每页显示数量,从数据集中获取指定页的数据
    public list<string> getdataforpage(list<string> datalist, int pagenumber, int pagesize) {
        int startindex = (pagenumber - 1) * pagesize;
        int endindex = math.min(startindex + pagesize, datalist.size());
        if (startindex >= endindex) {
            return new arraylist<>(); // 如果起始索引大于等于结束索引,返回空列表
        }
        return datalist.sublist(startindex, endindex);
    }
    // 示例用法
    public static void main(string[] args) {
        paginationwitharrayexample example = new paginationwitharrayexample();
        list<string> datalist = example.fetchdatafromdatabase(); // 模拟从数据库中获取数据
        int pagenumber = 2; // 第2页
        int pagesize = 10; // 每页显示10条数据
        list<string> pagedata = example.getdataforpage(datalist, pagenumber, pagesize);
        // 输出当前页的数据
        system.out.println("page " + pagenumber + " data:");
        for (string data : pagedata) {
            system.out.println(data);
        }
    }
}

在这个示例中,fetchdatafromdatabase 方法模拟从数据库中获取数据,返回一个包含了所有数据的列表。然后,getdataforpage 方法根据传入的页码和每页显示数量,从数据集中获取指定页的数据,返回一个包含了当前页数据的子列表。在示例的 main 方法中,演示了如何使用这两个方法来获取指定页的数据,并将其打印输出。

使用 mybatis-plus 进行分页

mybatis-plus进行分页的原理主要依赖于其内置的分页插件和page对象。
首先,mybatis-plus提供了分页插件,该插件会在mybatis执行sql查询之前进行拦截。当使用mybatis-plus进行分页查询时,分页插件会自动识别分页相关的参数,并对原始的sql语句进行改写,添加limit和offset子句,以实现物理分页。
其次,mybatis-plus中的page对象用于表示分页信息。这个对象包含了当前页码、每页记录数、总记录数等信息。在进行分页查询时,可以通过传递page对象给mybatis-plus的查询方法,来告诉mybatis-plus需要进行分页查询以及分页的具体参数。
当mybatis-plus执行分页查询时,它会根据page对象中的信息生成对应的分页sql语句,并通过数据库执行这个语句。数据库会根据limit和offset子句返回指定范围的结果集。
最后,mybatis-plus将查询结果封装到page对象中,并返回给调用者。这个page对象不仅包含了实际的查询结果列表,还包含了分页相关的信息,如总记录数、总页数等。这使得分页操作更加方便,同时也提高了代码的可维护性。
需要注意的是,mybatis-plus的分页实现是基于物理分页的,即直接在数据库层面进行分页处理,而不是在内存中处理。这种方式在处理大数据量时性能较好,避免了内存溢出的风险。
总结来说,mybatis-plus进行分页的原理是通过分页插件和page对象来实现物理分页,通过在sql语句中添加limit和offset子句来获取指定范围的结果集,并将结果封装到page对象中返回给调用者。
mybatis-plus 是 mybatis 的增强工具包,提供了很多便捷的功能,其中包括了分页功能。mybatis-plus 的分页功能可以轻松地实现物理分页,让分页操作变得更加简单。
首先,你需要在项目中引入 mybatis-plus 的依赖。在 maven 项目中,你可以在 pom.xml 文件中添加如下依赖:

<dependency>
    <groupid>com.baomidou</groupid>
    <artifactid>mybatis-plus-boot-starter</artifactid>
    <version>latest_version</version>
</dependency>

接下来,假设你有一个 usermapper 接口,用于操作用户信息。你可以在该接口中直接定义分页查询的方法,无需额外编写 xml 映射文件。

import com.baomidou.mybatisplus.core.mapper.basemapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.page;
import com.example.demo.entity.user;
public interface usermapper extends basemapper<user> {
    page<user> selectuserpage(page<user> page);
}

在该方法中,我们使用了 mybatis-plus 提供的 page 类来实现分页。page 类继承自 mybatis 的 rowbounds 类,它除了包含分页信息外,还包含了分页查询返回的数据列表。
然后,你可以在 service 层中调用这个方法来进行分页查询:

import com.baomidou.mybatisplus.extension.plugins.pagination.page;
import com.example.demo.entity.user;
import com.example.demo.mapper.usermapper;
import org.springframework.beans.factory.annotation.autowired;
import org.springframework.stereotype.service;
import java.util.list;
@service
public class userservice {
    @autowired
    private usermapper usermapper;
    public page<user> getuserpage(int pagenum, int pagesize) {
        page<user> page = new page<>(pagenum, pagesize);
        return usermapper.selectuserpage(page);
    }
}

在这个示例中,我们创建了一个新的 page 对象,并传入了当前页码和每页显示数量。然后调用 selectuserpage 方法进行分页查询,并将结果返回。
最后,在 controller 层中调用 service 方法并将结果返回给前端即可完成分页查询的操作。

import com.baomidou.mybatisplus.extension.plugins.pagination.page;
import com.example.demo.entity.user;
import com.example.demo.service.userservice;
import org.springframework.beans.factory.annotation.autowired;
import org.springframework.web.bind.annotation.getmapping;
import org.springframework.web.bind.annotation.requestparam;
import org.springframework.web.bind.annotation.restcontroller;
@restcontroller
public class usercontroller {
    @autowired
    private userservice userservice;
    @getmapping("/users")
    public page<user> getuserpage(@requestparam(defaultvalue = "1") int pagenum,
                                  @requestparam(defaultvalue = "10") int pagesize) {
        return userservice.getuserpage(pagenum, pagesize);
    }
}

通过 mybatis-plus,你可以很方便地实现分页查询,而无需编写繁琐的 sql 语句或者额外的 xml 映射文件。

mybatis物理分页和逻辑分页

mybatis中的物理分页和逻辑分页是两种不同的分页方式,它们在实现方式和性能上有显著的区别。
物理分页:
物理分页是在数据库层面上实现的分页,它依赖于数据库自身提供的分页功能。在mybatis中,物理分页通常是通过在sql语句中添加limit和offset子句来实现的。这种方式在查询数据库时,数据库会根据指定的偏移量和限制数直接返回分页后的结果,而不需要加载全部数据到内存中。因此,物理分页在处理大数据量时性能较好,避免了内存溢出的风险。然而,需要注意的是,不同的数据库可能具有不同的分页语法,因此在使用物理分页时需要考虑到数据库方言的问题。
逻辑分页:
逻辑分页则是在应用层面上实现的分页,它依赖于查询结果集。逻辑分页首先会查询出全部的数据,然后将这些数据加载到内存中,再根据分页要求筛选出合适的数据进行分页。这种方式在数据量较小时可能比较方便,但在处理大数据量时,会消耗大量的内存,并可能导致性能问题。因此,逻辑分页通常适用于数据量较小或对数据实时性要求不高的场景。
在实际应用中,选择物理分页还是逻辑分页需要根据具体的需求和场景来决定。对于大数据量或对数据性能要求较高的场景,建议使用物理分页以提高性能和避免内存溢出。而对于数据量较小或对数据实时性要求不高的场景,可以选择逻辑分页以简化实现过程。
此外,mybatis还提供了分页插件如pagehelper来简化分页操作的实现。这些插件内部实现了物理分页的逻辑,使得开发者可以更方便地进行分页操作,而无需手动编写复杂的分页sql语句。然而,在使用分页插件时,仍然需要注意插件的性能和兼容性等问题。

mybatis 手写一个 拦截器分页

mybatis 拦截器可以用于在 sql 执行前后进行一些额外的处理,例如实现分页功能。下面我会给出一个简单的示例,包含了 dao 层和业务层的代码。

假设你有一个 userdao 接口,其中定义了获取用户列表的方法:
public interface userdao {
    list<user> getuserlist();
}
接下来,我们创建一个拦截器来实现分页功能:
import org.apache.ibatis.executor.executor;
import org.apache.ibatis.mapping.boundsql;
import org.apache.ibatis.mapping.mappedstatement;
import org.apache.ibatis.plugin.*;
import org.apache.ibatis.session.resulthandler;
import org.apache.ibatis.session.rowbounds;
import java.util.properties;
@intercepts(@signature(type = executor.class, method = "query", args = {mappedstatement.class, object.class, rowbounds.class, resulthandler.class}))
public class paginationinterceptor implements interceptor {
    @override
    public object intercept(invocation invocation) throws throwable {
        object[] args = invocation.getargs();
        mappedstatement mappedstatement = (mappedstatement) args[0];
        object parameter = args[1];
        rowbounds rowbounds = (rowbounds) args[2];
        // 判断是否需要进行分页
        if (rowbounds != rowbounds.default) {
            boundsql boundsql = mappedstatement.getboundsql(parameter);
            string sql = boundsql.getsql();
            // 自己实现分页逻辑,这里简单起见,直接拼接 limit
            sql += " limit " + rowbounds.getoffset() + ", " + rowbounds.getlimit();
            boundsql newboundsql = new boundsql(mappedstatement.getconfiguration(), sql, boundsql.getparametermappings(), boundsql.getparameterobject());
            mappedstatement newmappedstatement = copyfrommappedstatement(mappedstatement, new boundsqlsqlsource(newboundsql));
            args[0] = newmappedstatement;
            args[2] = rowbounds.default;
        }
        return invocation.proceed();
    }
    private mappedstatement copyfrommappedstatement(mappedstatement ms, boundsqlsqlsource newsqlsource) {
        mappedstatement.builder builder = new mappedstatement.builder(ms.getconfiguration(), ms.getid(), newsqlsource, ms.getsqlcommandtype());
        builder.resource(ms.getresource());
        builder.fetchsize(ms.getfetchsize());
        builder.statementtype(ms.getstatementtype());
        builder.keygenerator(ms.getkeygenerator());
        builder.keyproperty(ms.getkeyproperty());
        builder.timeout(ms.gettimeout());
        builder.parametermap(ms.getparametermap());
        builder.resultmaps(ms.getresultmaps());
        builder.cache(ms.getcache());
        builder.flushcacherequired(ms.isflushcacherequired());
        builder.usecache(ms.isusecache());
        return builder.build();
    }
    @override
    public object plugin(object target) {
        return plugin.wrap(target, this);
    }
    @override
    public void setproperties(properties properties) {
        // 这里可以接收配置参数,但我们这里不需要配置参数
    }
    private static class boundsqlsqlsource implements org.apache.ibatis.mapping.sqlsource {
        private final boundsql boundsql;
        public boundsqlsqlsource(boundsql boundsql) {
            this.boundsql = boundsql;
        }
        @override
        public boundsql getboundsql(object parameterobject) {
            return boundsql;
        }
    }
}
然后,在你的 mybatis 配置文件中配置该拦截器:
<plugins>
    <plugin interceptor="your.package.name.paginationinterceptor"/>
</plugins>
最后,在业务代码中使用分页功能:
import org.apache.ibatis.session.rowbounds;
public class userservice {
    private final userdao userdao;
    public userservice(userdao userdao) {
        this.userdao = userdao;
    }
    public list<user> getusersbypage(int pagenum, int pagesize) {
        // 计算 offset
        int offset = (pagenum - 1) * pagesize;
        // 使用 rowbounds 进行分页
        rowbounds rowbounds = new rowbounds(offset, pagesize);
        return userdao.getuserlist(rowbounds);
    }
}

这样,当调用 getusersbypage 方法时,会自动进行分页查询。

到此这篇关于mybatis实现分页的文章就介绍到这了,更多相关mybatis实现分页内容请搜索代码网以前的文章或继续浏览下面的相关文章希望大家以后多多支持代码网!

(0)

相关文章:

版权声明:本文内容由互联网用户贡献,该文观点仅代表作者本人。本站仅提供信息存储服务,不拥有所有权,不承担相关法律责任。 如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 2386932994@qq.com 举报,一经查实将立刻删除。

发表评论

验证码:
Copyright © 2017-2025  代码网 保留所有权利. 粤ICP备2024248653号
站长QQ:2386932994 | 联系邮箱:2386932994@qq.com