mybatis攔截器案例之獲取結果集總條數


最近做的項目前端是外包出去的,所以在做查詢分頁的時候比較麻煩

我們需要先吧結果集的條數返回給前端,然后由前端根據頁面情況(當前頁碼,每頁顯示條數)將所需參數傳到后端。

由於在項目搭建的時候,是沒有考慮數據量比較大(結果集數量大於1W條,甚至達到30W條)的情況

(使用的VPN網絡比較慢,使用單元測試,1w條數據,需要30s左右才能返回到系統上,sql本身執行在秒內可以出結果,

所以不能先把結果集拿到系統中,再返回結果集的條數,然后分頁。所以需要另一個查詢,返回結果集的條數

現在項目已經存在很多查詢語句,項目使用的是mybatis,所有mybatis中就配了很多select(幾百個),每個都去加一個對應的查詢結果集條數的SQL,

不知道得吐多少老血(而且會讓項目的mapper配置,膨脹很多,這是不必要的損耗)

這種場景下,使用攔截器,在查詢中動態獲取SQL,添加查詢結果集的語句(select count(*) from (原來的sql)),就是合適的解決方法

這樣,只需要在請求參數中添加一個參數(根據項目情況,我是這樣設計的,慕課網上的案例是在select的id中添加指定字符串,如:“bypage”)

在攔截器中取出滿足條件的SQL,動態的添加上(select count(*) from (原來的sql)) 就可以返回結果集的條數。

同時引用了開源的mybatis插件Mybatis_PageHelper ,所有在使用攔截器的時候,加了一個判斷,是不是需要分頁的查詢

mybatis_config.xml 

<plugins>
        <plugin interceptor="com.utstar.bi.interceptors.SqlInterceptorCount">  <!-- 自己寫的那個攔截器 -->
            <property name="dialect" value="mysql"/> <!-- mysql的方言 -->
        </plugin>
    </plugins>

java

package com.utstar.bi.interceptors;

import org.apache.ibatis.executor.statement.StatementHandler;
import org.apache.ibatis.plugin.*;
import org.apache.ibatis.reflection.MetaObject;

import java.sql.Connection;
import java.util.HashMap;
import java.util.Properties;

/**
 * Created by Lenovo on 2017/6/17.
 */
@Intercepts({ @Signature(type = StatementHandler.class, method = "prepare", args = { Connection.class }) })
public class SqlInterceptorCount implements Interceptor {

    @Override
    public Object intercept(Invocation invocation) throws Throwable {

        StatementHandler statementHandler = (StatementHandler) invocation.getTarget();
        MetaObject metaStatementHandler = MetaObject.forObject(statementHandler);
        HashMap mapParam = (HashMap) metaStatementHandler.getValue("delegate.boundSql.parameterObject");
        /*
        * add by venn
        * if the request parameter with key count && value is sum
        * then this sql just return the sql count from result
        * 如果請求參數中有個值是count並且value是sum,就是我們需要攔截的查詢
        * mapParam.get("startItem") ==null :這句是因為同時引用了Mybatis_PageHelper
        *       插件,防止SQL交叉,做的安全過濾
        * */
        if (mapParam.get("startItem") ==null && mapParam.get("count") != null && mapParam.get("count").toString().equalsIgnoreCase("sum")) {
            // 從StatementHandler中取出查詢的SQL
            String sql = (String) metaStatementHandler.getValue("delegate.boundSql.sql"); //System.out.println("before sql = " +sql);
            // 獲取第一個from的坐標
            int index = sql.indexOf("from");
            // 將sql from坐標前的字符截斷,加上 select count(1) coun 查詢結果集條數的SQL
            sql = "select count(1) coun " + sql.substring(index); //System.out.println("after sql = " +sql);
            // 將修改的SQL放回StatementHandler中
            metaStatementHandler.setValue("delegate.boundSql.sql", sql);
        }
        // 繼續執行攔截之前的操作
        return invocation.proceed();
    }

    @Override
    public Object plugin(Object target) {
        /*
            根據Intercepts注解,攔截 StatementHandler 的prepare 方法
         */
        return Plugin.wrap(target, this);
    }

    @Override
    public void setProperties(Properties properties) {

    }
}

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM