网站建设知识
MyBatis Generator实现MySQL分页插件
2025-07-22 09:58  点击:0

MyBatis Generator是一个非常方便的代码生成工具,它能够根据表结构生成CRUD代码,可以满足大部分需求。但是唯一让人不爽的是,生成的代码中的数据库查询没有分页功能。本文介绍如何让MyBatis Generator生成的代码具有分页功能。

MyBatis Generator结合Maven的配置和使用

在实现分页之前,首先简单介绍MyBatis Generator如何使用。

MyBatis Generator配置文件

MyBatis Generator通常会有一个xml配置文件,用来指定连接的数据库、哪些表、如何生成代码。下面给出一份简单的配置,文件命名为generatorConfig.xml:

    ntext   targetruntime="MyBatis3">        nnection connectionurl="jdbc:mysql://localhost:3306/yourdb?useUnicode=true&characterEncoding=UTF-8" driver password="password" userid="user">                        

Maven配置

官网文档中提供了四种MyBatis Generator生成代码的运行方式:命令行、使用Ant、使用Maven、Java编码。本文采用Maven插件mybatis-generator-maven-plugin来运行MyBatis Generator。下面给出一份简单的pom.xml的配置:

                        org.mybatis.generator            mybatis-generator-maven-plugin            1.3.2                                                mysql                    mysql-connector-java                    5.1.34                                                        true                        

以上配置完成后,可以通过运行mvn mybatis-generator:generate命令来生成代码。当然,如果只有上面的这些配置,生成的代码是不支持分页的。

RowBoundsPlugin

MyBatis Generator可以通过插件机制来扩展其功能,其中RowBoundsPlugin是MyBatis Generator中自带的一个分页插件。可以在MyBatis Generator配置文件generatorConfig.xml中添加这个插件:

ntext   targetruntime="MyBatis3">        ...

再次运行mvn mybatis-generator:generate生成代码,此时会发现生成的Mapper中会加入一个新的方法:selectByExampleWithRowbounds(XxxExample example, RowBounds rowBounds),可以在代码中调用这个方法来实现分页:

int offset = 100;int limit = 25;RowBounds rowBounds = new RowBounds(offset, limit);List list = xxxMapper.selectByExampleWithRowbounds(example, rowBounds);

RowBounds的构造方法new RowBounds(offset, limit)中的offset、limit参数就相当于MySQL的select语句limit后的offset和rows。如果此时仔细观察一下日志打出来的SQL语句或者看下生成的XxxMapper.xml文件中的selectByExampleWithRowbounds元素,可以发现select语句并没有使用limit。实际上RowBounds原理是通过ResultSet的游标来实现分页,也就是并不是用select语句的limit分页而是用Java代码分页,查询语句的结果集会包含符合查询条件的所有数据,使用不慎会导致性能问题,所以并不推荐使用RowBoundsPlugin来实现分页。

limit分页插件实现

在实现MySQL分页时更推荐使用select语句的limit来实现分页,然而MyBatis Generator目前并没有提供这样的插件。好在MyBatis Generator支持插件扩展,我们可以自己实现一个基于limit来分页的插件。

实现思路

在生成的XxxExample中加入两个属性limit和offset,同时加上set和get方法。也就是需要生成以下代码:

private Integer limit;private Integer offset;public void setLimit(Integer limit) {    this.limit = limit;}public Integer getLimit() {    return limit;}public void setOffset(Integer offset) {    this.offset = offset;}public Integer getOffset() {    return offset;}

XxxMapper.xml中在通过selectByExample查询时,添加limit:

插件实现代码

package com.xxg.mybatis.plugins;import java.util.List;import org.mybatis.generator.api.IntrospectedTable;import org.mybatis.generator.api.PluginAdapter;import org.mybatis.generator.api.dom.java.Field;import org.mybatis.generator.api.dom.java.FullyQualifiedJavaType;import org.mybatis.generator.api.dom.java.JavaVisibility;import org.mybatis.generator.api.dom.java.Method;import org.mybatis.generator.api.dom.java.Parameter;import org.mybatis.generator.api.dom.java.PrimitiveTypeWrapper;import org.mybatis.generator.api.dom.java.TopLevelClass;import org.mybatis.generator.api.dom.xml.Attribute;import org.mybatis.generator.api.dom.xml.TextElement;import org.mybatis.generator.api.dom.xml.XmlElement;public class MySQLLimitPlugin extends PluginAdapter {    @Override    public boolean validate(List list) {        return true;    }        @Override    public boolean modelExampleClassGenerated(TopLevelClass topLevelClass, IntrospectedTable introspectedTable) {        PrimitiveTypeWrapper integerWrapper = FullyQualifiedJavaType.getIntInstance().getPrimitiveTypeWrapper();        Field limit = new Field();        limit.setName("limit");        limit.setVisibility(JavaVisibility.PRIVATE);        limit.setType(integerWrapper);        topLevelClass.addField(limit);        Method setLimit = new Method();        setLimit.setVisibility(JavaVisibility.PUBLIC);        setLimit.setName("setLimit");        setLimit.addParameter(new Parameter(integerWrapper, "limit"));        setLimit.addBodyLine("this.limit = limit;");        topLevelClass.addMethod(setLimit);        Method getLimit = new Method();        getLimit.setVisibility(JavaVisibility.PUBLIC);        getLimit.setReturnType(integerWrapper);        getLimit.setName("getLimit");        getLimit.addBodyLine("return limit;");        topLevelClass.addMethod(getLimit);        Field offset = new Field();        offset.setName("offset");        offset.setVisibility(JavaVisibility.PRIVATE);        offset.setType(integerWrapper);        topLevelClass.addField(offset);        Method setOffset = new Method();        setOffset.setVisibility(JavaVisibility.PUBLIC);        setOffset.setName("setOffset");        setOffset.addParameter(new Parameter(integerWrapper, "offset"));        setOffset.addBodyLine("this.offset = offset;");        topLevelClass.addMethod(setOffset);        Method getOffset = new Method();        getOffset.setVisibility(JavaVisibility.PUBLIC);        getOffset.setReturnType(integerWrapper);        getOffset.setName("getOffset");        getOffset.addBodyLine("return offset;");        topLevelClass.addMethod(getOffset);        return true;    }        @Override    public boolean sqlMapSelectByExampleWithoutBLOBsElementGenerated(XmlElement element,            IntrospectedTable introspectedTable) {        XmlElement ifLimitNotNullElement = new XmlElement("if");        ifLimitNotNullElement.addAttribute(new Attribute("test", "limit != null"));        XmlElement ifOffsetNotNullElement = new XmlElement("if");        ifOffsetNotNullElement.addAttribute(new Attribute("test", "offset != null"));        ifOffsetNotNullElement.addElement(new TextElement("limit ${offset}, ${limit}"));        ifLimitNotNullElement.addElement(ifOffsetNotNullElement);        XmlElement ifOffsetNullElement = new XmlElement("if");        ifOffsetNullElement.addAttribute(new Attribute("test", "offset == null"));        ifOffsetNullElement.addElement(new TextElement("limit ${limit}"));        ifLimitNotNullElement.addElement(ifOffsetNullElement);        element.addElement(ifLimitNotNullElement);        return true;    }}

插件的使用

在MyBatis Generator配置文件中配置plugin:

ntext   targetruntime="MyBatis3">        ...

如果直接加上以上配置运行mvn mybatis-generator:generate肯定会出现找不到这个插件的错误:

java.lang.ClassNotFoundException: com.xxg.mybatis.plugins.MySQLLimitPlugin

为了方便大家的使用,我已经把插件打包上传到GitHub,可以在pom.xml直接依赖使用:

            mybatis-generator-limit-plugin-mvn-repo        https://raw.github/wucao/mybatis-generator-limit-plugin/mvn-repo/                            org.mybatis.generator            mybatis-generator-maven-plugin            1.3.2                                                mysql                    mysql-connector-java                    5.1.34                                                    com.xxg                    mybatis-generator-plugin                    1.0.0                                                        true                        

此时运行mvn mybatis-generator:generate命令可以成功生成代码。

使用生成的代码分页

XxxExample example = new XxxExample();...example.setLimit(10); // page size limitexample.setOffset(20); // offsetList list = xxxMapper.selectByExample(example);

以上代码运行时执行的SQL是:select ... limit 20, 10

XxxExample example = new XxxExample();...example.setLimit(10); // limitList list = xxxMapper.selectByExample(example);

以上代码运行时执行的SQL是:select ... limit 10