MyBatis Generator分頁插件RowBoundsPlugin坑

一、Mybatis Generator設置分頁

Mybatis Generator沒有設置分頁,但自帶了個RowBoundsPlugin分頁插件,故而配置

<plugin type="org.mybatis.generator.plugins.RowBoundsPlugin"/>

在mysql數據庫進行查詢的表分頁10條,查很久花費了9s,表的數據也只是十幾萬行。百思不得其解,查看RowBoundsPlugin生成的代碼,如下:

public interface IDomainDao {

    //省略其他代碼
    @SelectProvider(type=DomainSqlProvider.class, method="selectByExample")
    @Results({
        @Result(column="id", property="id", jdbcType=JdbcType.INTEGER, id=true),
        @Result(column="domain", property="domain", jdbcType=JdbcType.VARCHAR)
    })
    List<Domain> selectByExampleWithRowbounds(DomainExample example, RowBounds rowBounds);
}
public class DomainSqlProvider {

    //省略其他代碼
    public String selectByExample(DomainExample example) {
        SQL sql = new SQL();
        if (example != null && example.isDistinct()) {
            sql.SELECT_DISTINCT("id");
        } else {
            sql.SELECT("id");
        }
        sql.SELECT("domain");
  
        sql.FROM("domain");
        applyWhere(sql, example, false);
        
        if (example != null && example.getOrderByClause() != null) {
            sql.ORDER_BY(example.getOrderByClause());
        }
        
        return sql.toString();
    }
}

selectByExample方法裏面沒有使用limit進行分頁,使用mybatis自帶的RowBounds功能進行內存分頁。故而查詢十條數據,其實是把整張表符合要求的數據都查詢出來了,在程序的內存進行截取,故而花費了9s。

 

二、解決方案

對Mysql

(1)使用example.setOrderByClause()方法進行sql注入limit分頁

(2)重些插件改造example進行分頁

public class MySqlLimitPlugin extends PluginAdapter {

    @Override
    public boolean validate(List<String> list) {
        return true;
    }

    /**
     * Example類添加offset和limit屬性和set、get方法
     */
    @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;
    }

    /**
     * Mapper.xml的selectByExampleWithoutBLOBs添加limit
     */
    @Override
    public boolean sqlMapSelectByExampleWithoutBLOBsElementGenerated(XmlElement element,
                                                                     IntrospectedTable introspectedTable) {

        addXmlLimit(element);

        return true;
    }

    /**
     * Mapper.xml的selectByExampleWithBLOBs添加limit
     */    
    @Override
    public boolean sqlMapSelectByExampleWithBLOBsElementGenerated(XmlElement element,
                                                                  IntrospectedTable introspectedTable) {

        addXmlLimit(element);

        return true;
    }

    private void addXmlLimit(XmlElement element) {
        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);
    }


    /**
     * 註解selectByExampleWithBLOBs方法生成分頁
     */
    public boolean providerSelectByExampleWithBLOBsMethodGenerated(Method method, TopLevelClass topLevelClass, IntrospectedTable introspectedTable) {

        addAnnotationLimit(method, topLevelClass, introspectedTable);
        return super.providerSelectByExampleWithBLOBsMethodGenerated(method, topLevelClass, introspectedTable);
    }

    /**
     * 註解selectByExampleWithoutBLOBs方法生成分頁
     */
    public boolean providerSelectByExampleWithoutBLOBsMethodGenerated(Method method, TopLevelClass topLevelClass, IntrospectedTable introspectedTable) {

        addAnnotationLimit(method, topLevelClass, introspectedTable);
        return super.providerSelectByExampleWithoutBLOBsMethodGenerated(method, topLevelClass, introspectedTable);
    }

    private void addAnnotationLimit(Method method, TopLevelClass topLevelClass, IntrospectedTable introspectedTable) {
        
        List<String> limits = Arrays.asList(
                "if (example != null && example.getLimit() != null) {",
                "if (example.getOffset() != null) {",
                "sql.OFFSET(example.getOffset());",
                "}",
                "sql.LIMIT(example.getLimit());",
                "}"
        );

        method.addBodyLines(method.getBodyLines().size() - 1, limits);
    }

}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章