国产av日韩一区二区三区精品,成人性爱视频在线观看,国产,欧美,日韩,一区,www.成色av久久成人,2222eeee成人天堂

Table des matières
La méthode spécifique de pagination mybatis
Maison Java JavaBase Plusieurs fa?ons de paginer dans mybatis

Plusieurs fa?ons de paginer dans mybatis

Jan 04, 2023 pm 04:23 PM
mybatis

Méthode de pagination Mybatis?: 1. Utilisez des tableaux pour la pagination. Interrogez d'abord toutes les données, puis interceptez les parties requises de la liste. 2. Utilisez l'instruction SQL pour effectuer la pagination et ajoutez l'instruction de pagination limite après l'instruction sql. 3. Utilisez l'intercepteur pour la pagination et ajoutez l'instruction limit à la fin de l'instruction SQL via l'intercepteur pour effectuer des requêtes de pagination. 4. Pour utiliser RowBounds pour implémenter la pagination, vous devez obtenir toutes les données qualifiées à la fois, puis exploiter le Big Data en mémoire pour obtenir l'effet de pagination.

Plusieurs fa?ons de paginer dans mybatis

L'environnement d'exploitation de ce tutoriel : système windows7, java8, ordinateur Dell G3.

Les méthodes de pagination mybatis peuvent être divisées en deux grandes catégories?:

1. La pagination logique

2 La pagination physique

La méthode spécifique de pagination mybatis

  • La pagination à l'aide de tableaux (logiques). pagination)

  • Utilisez des instructions SQL pour la pagination (pagination physique)

  • Paging d'intercepteur (pagination physique) Utilisez l'intercepteur pour ajouter une instruction limit à la fin de l'instruction SQL pour interroger, une fois pour toutes, le meilleur

  • RowBounds implémente la pagination (pagination logique)

1. Pagination à l'aide de tableaux

Principe?: lors de l'exécution d'une opération de requête de base de données, obtenez tous les enregistrements qui remplissent les conditions dans la base de données, enregistrez dans le tableau temporaire de l'application, puis utilisez la méthode subList de List pour obtenir tous les enregistrements qui remplissent les conditions.

Implémentation?:

Tout d'abord, créez l'interface StudentMapper au niveau de la couche dao pour les opérations de base de données. Définissez la méthode de requête pour parcourir le tableau dans l'interface, comme indiqué ci-dessous?:

 List<Student> queryStudentsByArray();

La méthode est très simple, c'est-à-dire obtenir toutes les données, les recevoir via la liste, puis effectuer l'opération de pagination.

Créez le fichier StudentMapper.xml et écrivez l'instruction SQL de requête?:

 <select id="queryStudentsByArray"  resultMap="studentmapper">
        select * from student
 </select>

On peut voir que lors de l'écriture de l'instruction SQL, nous n'avons effectué aucune opération liée à la pagination. Toutes les informations sur les étudiants peuvent être trouvées ici.

Ensuite, obtenez les données dans la couche de service et implémentez la pagination :

Définissez l'interface IStuService et définissez la méthode de pagination :

List<Student> queryStudentsByArray(int currPage, int pageSize);

En recevant le paramètre currPage, il indique quelle page de données est affichée, et pageSize indique le numéro des éléments de données affichés sur chaque page.

Créez la classe d'implémentation de l'interface IStuService StuServiceIml pour implémenter la méthode et paginez le tableau obtenu via currPage et pageSize?:

 @Override
    public List<Student> queryStudentsByArray(int currPage, int pageSize) {
        List<Student> students = studentMapper.queryStudentsByArray();
//        從第幾條數(shù)據(jù)開始
        int firstIndex = (currPage - 1) * pageSize;
//        到第幾條數(shù)據(jù)結(jié)束
        int lastIndex = currPage * pageSize;
        return students.subList(firstIndex, lastIndex);
    }

Obtenez toutes les données entre les deux index via la méthode subList.

Enfin, créez une méthode de test dans le contr?leur?:

  @ResponseBody
    @RequestMapping("/student/array/{currPage}/{pageSize}")
    public List<Student> getStudentByArray(@PathVariable("currPage") int currPage, @PathVariable("pageSize") int pageSize) {
        List<Student> student = StuServiceIml.queryStudentsByArray(currPage, pageSize);
        return student;
    }

Obtenez les données spécifiées via currPage et pageSize transmis par l'utilisateur.

Test?:

Nous obtenons d'abord toutes les données obtenues avant que l'effet de pagination ne soit implémenté, comme indiqué ci-dessous?:

Plusieurs fa?ons de paginer dans mybatis

Ensuite, entrez http://localhost:8080/student/ dans le navigateur student/ array/1/2Le test implémente les données de pagination. Obtenez les données sur la première page et affichez deux éléments de données sur chaque page. http://localhost:8080/student/student/array/1/2測試實現(xiàn)了分頁后的數(shù)據(jù)。獲取第一頁的數(shù)據(jù),每頁顯示兩條數(shù)據(jù)。

結(jié)果如下:

Plusieurs fa?ons de paginer dans mybatis 輸出的是指定的從第0-2條數(shù)據(jù),可見我們通過數(shù)組分頁的功能是成功的。(這里因為用到了關(guān)聯(lián)查詢,所以看起來數(shù)據(jù)可能比較多)

缺點:數(shù)據(jù)庫查詢并返回所有的數(shù)據(jù),而我們需要的只是極少數(shù)符合要求的數(shù)據(jù)。當(dāng)數(shù)據(jù)量少時,還可以接受。當(dāng)數(shù)據(jù)庫數(shù)據(jù)量過大時,每次查詢對數(shù)據(jù)庫和程序的性能都會產(chǎn)生極大的影響。

2、借助Sql語句進(jìn)行分頁

在了解到通過數(shù)組分頁的缺陷后,我們發(fā)現(xiàn)不能每次都對數(shù)據(jù)庫中的所有數(shù)據(jù)都檢索。然后在程序中對獲取到的大量數(shù)據(jù)進(jìn)行二次操作,這樣對空間和性能都是極大的損耗。所以我們希望能直接在數(shù)據(jù)庫語言中只檢索符合條件的記錄,不需要在通過程序?qū)ζ渥魈幚怼_@時,Sql語句分頁技術(shù)橫空出世。

實現(xiàn):通過sql語句實現(xiàn)分頁也是非常簡單的,只是需要改變我們查詢的語句就能實現(xiàn)了,即在sql語句后面添加limit分頁語句。

首先還是在StudentMapper接口中添加sql語句查詢的方法,如下:

List<Student> queryStudentsBySql(Map<String,Object> data);

然后在StudentMapper.xml文件中編寫sql語句通過limiy關(guān)鍵字進(jìn)行分頁:

 <select id="queryStudentsBySql" parameterType="map" resultMap="studentmapper">
        select * from student limit #{currIndex} , #{pageSize}
</select>

接下來還是在IStuService接口中定義方法,并且在StuServiceIml中對sql分頁實現(xiàn)。

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;

所以在service中計算出currIndex:要開始查詢的第一條記錄的索引。

測試:

在瀏覽器輸入http://localhost:8080/student/student/sql/1/2

Les résultats sont les suivants?:

2 .png La sortie correspond aux données spécifiées de 0 à 2, ce qui montre que notre fonction de pagination via le tableau a réussi. (étant donné que des requêtes associées sont utilisées ici, il semble qu'il puisse y avoir beaucoup de données) ????Inconvénients?: La base de données interroge et renvoie toutes les données, et nous n'avons besoin que d'une très petite quantité de données qui répondent aux exigences. Lorsque la quantité de données est faible, cela est acceptable. Lorsque la quantité de données de la base de données est trop importante, chaque requête aura un impact important sur les performances de la base de données et du programme. ????????2. Utilisez les instructions SQL pour la pagination ????????Après avoir pris connaissance des inconvénients de la pagination dans les tableaux, nous avons constaté que nous ne pouvons pas récupérer toutes les données de la base de données à chaque fois. Effectuez ensuite des opérations secondaires sur la grande quantité de données obtenues dans le programme, ce qui consomme beaucoup d'espace et de performances. Par conséquent, nous espérons récupérer directement uniquement les enregistrements qui remplissent les conditions dans le langage de la base de données sans les traiter via le programme. à cette époque, la technologie de pagination des instructions SQL a vu le jour. ????Implémentation : Il est également très simple d'implémenter la pagination via des instructions SQL. Il nous suffit de modifier l'instruction de notre requête pour y parvenir, c'est-à-dire d'ajouter une instruction de pagination limite après l'instruction sql. ????Tout d'abord, ajoutez la méthode de requête d'instruction SQL dans l'interface StudentMapper, comme suit : ??
package com.cbg.interceptor;

import org.apache.ibatis.executor.Executor;
import org.apache.ibatis.executor.parameter.ParameterHandler;
import org.apache.ibatis.executor.resultset.ResultSetHandler;
import org.apache.ibatis.executor.statement.StatementHandler;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.plugin.*;
import org.apache.ibatis.reflection.MetaObject;
import org.apache.ibatis.reflection.SystemMetaObject;

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

/**
 * Created by chenboge on 2017/5/7.
 * <p>
 * Email:baigegechen@gmail.com
 * <p>
 * description:
 */

/**
 * @Intercepts 說明是一個攔截器
 * @Signature 攔截器的簽名
 * type 攔截的類型 四大對象之一( Executor,ResultSetHandler,ParameterHandler,StatementHandler)
 * method 攔截的方法
 * args 參數(shù)
 */
@Intercepts({@Signature(type = StatementHandler.class, method = "prepare", args = {Connection.class, Integer.class})})
public class MyPageInterceptor implements Interceptor {

//每頁顯示的條目數(shù)
    private int pageSize;
//當(dāng)前現(xiàn)實的頁數(shù)
    private int currPage;

    private String dbType;


    @Override
    public Object intercept(Invocation invocation) throws Throwable {
        //獲取StatementHandler,默認(rèn)是RoutingStatementHandler
        StatementHandler statementHandler = (StatementHandler) invocation.getTarget();
        //獲取statementHandler包裝類
        MetaObject MetaObjectHandler = SystemMetaObject.forObject(statementHandler);

        //分離代理對象鏈
        while (MetaObjectHandler.hasGetter("h")) {
            Object obj = MetaObjectHandler.getValue("h");
            MetaObjectHandler = SystemMetaObject.forObject(obj);
        }

        while (MetaObjectHandler.hasGetter("target")) {
            Object obj = MetaObjectHandler.getValue("target");
            MetaObjectHandler = SystemMetaObject.forObject(obj);
        }

        //獲取連接對象
        //Connection connection = (Connection) invocation.getArgs()[0];


        //object.getValue("delegate");  獲取StatementHandler的實現(xiàn)類

        //獲取查詢接口映射的相關(guān)信息
        MappedStatement mappedStatement = (MappedStatement) MetaObjectHandler.getValue("delegate.mappedStatement");
        String mapId = mappedStatement.getId();

        //statementHandler.getBoundSql().getParameterObject();

        //攔截以.ByPage結(jié)尾的請求,分頁功能的統(tǒng)一實現(xiàn)
        if (mapId.matches(".+ByPage$")) {
            //獲取進(jìn)行數(shù)據(jù)庫操作時管理參數(shù)的handler
            ParameterHandler parameterHandler = (ParameterHandler) MetaObjectHandler.getValue("delegate.parameterHandler");
            //獲取請求時的參數(shù)
            Map<String, Object> paraObject = (Map<String, Object>) parameterHandler.getParameterObject();
            //也可以這樣獲取
            //paraObject = (Map<String, Object>) statementHandler.getBoundSql().getParameterObject();

            //參數(shù)名稱和在service中設(shè)置到map中的名稱一致
            currPage = (int) paraObject.get("currPage");
            pageSize = (int) paraObject.get("pageSize");

            String sql = (String) MetaObjectHandler.getValue("delegate.boundSql.sql");
            //也可以通過statementHandler直接獲取
            //sql = statementHandler.getBoundSql().getSql();

            //構(gòu)建分頁功能的sql語句
            String limitSql;
            sql = sql.trim();
            limitSql = sql + " limit " + (currPage - 1) * pageSize + "," + pageSize;

            //將構(gòu)建完成的分頁sql語句賦值個體&#39;delegate.boundSql.sql&#39;,偷天換日
            MetaObjectHandler.setValue("delegate.boundSql.sql", limitSql);
        }
//調(diào)用原對象的方法,進(jìn)入責(zé)任鏈的下一級
        return invocation.proceed();
    }


    //獲取代理對象
    @Override
    public Object plugin(Object o) {
    //生成object對象的動態(tài)代理對象
        return Plugin.wrap(o, this);
    }

    //設(shè)置代理對象的參數(shù)
    @Override
    public void setProperties(Properties properties) {
//如果項目中分頁的pageSize是統(tǒng)一的,也可以在這里統(tǒng)一配置和獲取,這樣就不用每次請求都傳遞pageSize參數(shù)了。參數(shù)是在配置攔截器時配置的。
        String limit1 = properties.getProperty("limit", "10");
        this.pageSize = Integer.valueOf(limit1);
        this.dbType = properties.getProperty("dbType", "mysql");
    }
}
?? Ensuite, écrivez l'instruction SQL dans StudentMapper et implémentez la pagination SQL dans StuServiceIml. ??
private final StatementHandler delegate;

    public RoutingStatementHandler(Executor executor, MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) {
        switch(RoutingStatementHandler.SyntheticClass_1.$SwitchMap$org$apache$ibatis$mapping$StatementType[ms.getStatementType().ordinal()]) {
        case 1:
            this.delegate = new SimpleStatementHandler(executor, ms, parameter, rowBounds, resultHandler, boundSql);
            break;
        case 2:
            this.delegate = new PreparedStatementHandler(executor, ms, parameter, rowBounds, resultHandler, boundSql);
            break;
        case 3:
            this.delegate = new CallableStatementHandler(executor, ms, parameter, rowBounds, resultHandler, boundSql);
            break;
        default:
            throw new ExecutorException("Unknown statement type: " + ms.getStatementType());
        }

    }
    public abstract class BaseStatementHandler implements StatementHandler {
    protected final Configuration configuration;
    protected final ObjectFactory objectFactory;
    protected final TypeHandlerRegistry typeHandlerRegistry;
    protected final ResultSetHandler resultSetHandler;
    protected final ParameterHandler parameterHandler;
    protected final Executor executor;
    protected final MappedStatement mappedStatement;
    protected final RowBounds rowBounds;
    protected BoundSql boundSql;

    protected BaseStatementHandler(Executor executor, MappedStatement mappedStatement, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) {
        this.configuration = mappedStatement.getConfiguration();
        this.executor = executor;
        this.mappedStatement = mappedStatement;
        this.rowBounds = rowBounds;
        this.typeHandlerRegistry = this.configuration.getTypeHandlerRegistry();
        this.objectFactory = this.configuration.getObjectFactory();
        if(boundSql == null) {
            this.generateKeys(parameterObject);
            boundSql = mappedStatement.getBoundSql(parameterObject);
        }

        this.boundSql = boundSql;
        this.parameterHandler = this.configuration.newParameterHandler(mappedStatement, parameterObject, boundSql);
        this.resultSetHandler = this.configuration.newResultSetHandler(executor, mappedStatement, rowBounds, this.parameterHandler, resultHandler, boundSql);
    }
??L'instruction de pagination SQL est la suivante?: select * from table limit index, pageSize;????Donc currIndex est calculé dans le service?: l'index du premier enregistrement pour lequel l'interrogation est lancée. ????Test?: ????Entrez http://localhost:8080/student/sql/1/2 dans le navigateur pour obtenir les données sur la première page, et deux éléments de données seront affichés sur chaque page. ????Résultat?: ??

Plusieurs fa?ons de paginer dans mybatis

從輸出結(jié)果可以看出和數(shù)組分頁的結(jié)果是一致的,因此sql語句的分頁也是沒問題的。

缺點:雖然這里實現(xiàn)了按需查找,每次檢索得到的是指定的數(shù)據(jù)。但是每次在分頁的時候都需要去編寫limit語句,很冗余。而且不方便統(tǒng)一管理,維護(hù)性較差。所以我們希望能夠有一種更方便的分頁實現(xiàn)。

3、攔截器分頁

上面提到的數(shù)組分頁和sql語句分頁都不是我們今天講解的重點,今天需要實現(xiàn)的是利用攔截器達(dá)到分頁的效果。自定義攔截器實現(xiàn)了攔截所有以ByPage結(jié)尾的查詢語句,并且利用獲取到的分頁相關(guān)參數(shù)統(tǒng)一在sql語句后面加上limit分頁的相關(guān)語句,一勞永逸。不再需要在每個語句中單獨去配置分頁相關(guān)的參數(shù)了。。

首先我們看一下攔截器的具體實現(xiàn),在這里我們需要攔截所有以ByPage結(jié)尾的所有查詢語句,因此要使用該攔截器實現(xiàn)分頁功能,那么再定義名稱的時候需要滿足它攔截的規(guī)則(以ByPage結(jié)尾),如下所示:

package com.cbg.interceptor;

import org.apache.ibatis.executor.Executor;
import org.apache.ibatis.executor.parameter.ParameterHandler;
import org.apache.ibatis.executor.resultset.ResultSetHandler;
import org.apache.ibatis.executor.statement.StatementHandler;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.plugin.*;
import org.apache.ibatis.reflection.MetaObject;
import org.apache.ibatis.reflection.SystemMetaObject;

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

/**
 * Created by chenboge on 2017/5/7.
 * <p>
 * Email:baigegechen@gmail.com
 * <p>
 * description:
 */

/**
 * @Intercepts 說明是一個攔截器
 * @Signature 攔截器的簽名
 * type 攔截的類型 四大對象之一( Executor,ResultSetHandler,ParameterHandler,StatementHandler)
 * method 攔截的方法
 * args 參數(shù)
 */
@Intercepts({@Signature(type = StatementHandler.class, method = "prepare", args = {Connection.class, Integer.class})})
public class MyPageInterceptor implements Interceptor {

//每頁顯示的條目數(shù)
    private int pageSize;
//當(dāng)前現(xiàn)實的頁數(shù)
    private int currPage;

    private String dbType;


    @Override
    public Object intercept(Invocation invocation) throws Throwable {
        //獲取StatementHandler,默認(rèn)是RoutingStatementHandler
        StatementHandler statementHandler = (StatementHandler) invocation.getTarget();
        //獲取statementHandler包裝類
        MetaObject MetaObjectHandler = SystemMetaObject.forObject(statementHandler);

        //分離代理對象鏈
        while (MetaObjectHandler.hasGetter("h")) {
            Object obj = MetaObjectHandler.getValue("h");
            MetaObjectHandler = SystemMetaObject.forObject(obj);
        }

        while (MetaObjectHandler.hasGetter("target")) {
            Object obj = MetaObjectHandler.getValue("target");
            MetaObjectHandler = SystemMetaObject.forObject(obj);
        }

        //獲取連接對象
        //Connection connection = (Connection) invocation.getArgs()[0];


        //object.getValue("delegate");  獲取StatementHandler的實現(xiàn)類

        //獲取查詢接口映射的相關(guān)信息
        MappedStatement mappedStatement = (MappedStatement) MetaObjectHandler.getValue("delegate.mappedStatement");
        String mapId = mappedStatement.getId();

        //statementHandler.getBoundSql().getParameterObject();

        //攔截以.ByPage結(jié)尾的請求,分頁功能的統(tǒng)一實現(xiàn)
        if (mapId.matches(".+ByPage$")) {
            //獲取進(jìn)行數(shù)據(jù)庫操作時管理參數(shù)的handler
            ParameterHandler parameterHandler = (ParameterHandler) MetaObjectHandler.getValue("delegate.parameterHandler");
            //獲取請求時的參數(shù)
            Map<String, Object> paraObject = (Map<String, Object>) parameterHandler.getParameterObject();
            //也可以這樣獲取
            //paraObject = (Map<String, Object>) statementHandler.getBoundSql().getParameterObject();

            //參數(shù)名稱和在service中設(shè)置到map中的名稱一致
            currPage = (int) paraObject.get("currPage");
            pageSize = (int) paraObject.get("pageSize");

            String sql = (String) MetaObjectHandler.getValue("delegate.boundSql.sql");
            //也可以通過statementHandler直接獲取
            //sql = statementHandler.getBoundSql().getSql();

            //構(gòu)建分頁功能的sql語句
            String limitSql;
            sql = sql.trim();
            limitSql = sql + " limit " + (currPage - 1) * pageSize + "," + pageSize;

            //將構(gòu)建完成的分頁sql語句賦值個體&#39;delegate.boundSql.sql&#39;,偷天換日
            MetaObjectHandler.setValue("delegate.boundSql.sql", limitSql);
        }
//調(diào)用原對象的方法,進(jìn)入責(zé)任鏈的下一級
        return invocation.proceed();
    }


    //獲取代理對象
    @Override
    public Object plugin(Object o) {
    //生成object對象的動態(tài)代理對象
        return Plugin.wrap(o, this);
    }

    //設(shè)置代理對象的參數(shù)
    @Override
    public void setProperties(Properties properties) {
//如果項目中分頁的pageSize是統(tǒng)一的,也可以在這里統(tǒng)一配置和獲取,這樣就不用每次請求都傳遞pageSize參數(shù)了。參數(shù)是在配置攔截器時配置的。
        String limit1 = properties.getProperty("limit", "10");
        this.pageSize = Integer.valueOf(limit1);
        this.dbType = properties.getProperty("dbType", "mysql");
    }
}

上面即是攔截器功能的實現(xiàn),在intercept方法中獲取到select標(biāo)簽和sql語句的相關(guān)信息,攔截所有以ByPage結(jié)尾的select查詢,并且統(tǒng)一在查詢語句后面添加limit分頁的相關(guān)語句,統(tǒng)一實現(xiàn)分頁功能。

重點詳解:

StatementHandler是一個接口,而我們在代碼中通過StatementHandler statementHandler = (StatementHandler) invocation.getTarget();獲取到的是StatementHandler默認(rèn)的實現(xiàn)類RoutingStatementHandler。而RoutingStatementHandler只是一個中間代理,他不會提供具體的方法。那你可能會納悶了,攔截器中基本上是依賴statementHandler獲取各種對象和屬性的,沒有具體屬性和方法怎么行??接著看下面代碼:

private final StatementHandler delegate;

    public RoutingStatementHandler(Executor executor, MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) {
        switch(RoutingStatementHandler.SyntheticClass_1.$SwitchMap$org$apache$ibatis$mapping$StatementType[ms.getStatementType().ordinal()]) {
        case 1:
            this.delegate = new SimpleStatementHandler(executor, ms, parameter, rowBounds, resultHandler, boundSql);
            break;
        case 2:
            this.delegate = new PreparedStatementHandler(executor, ms, parameter, rowBounds, resultHandler, boundSql);
            break;
        case 3:
            this.delegate = new CallableStatementHandler(executor, ms, parameter, rowBounds, resultHandler, boundSql);
            break;
        default:
            throw new ExecutorException("Unknown statement type: " + ms.getStatementType());
        }

    }

原來它是通過不同的MappedStatement創(chuàng)建不同的StatementHandler實現(xiàn)類對象處理不同的情況。這里的到的StatementHandler實現(xiàn)類才是真正服務(wù)的??吹竭@里,你可能就會明白MappedStatement mappedStatement = (MappedStatement) MetaObjectHandler.getValue("delegate.mappedStatement");中delegate的來源了吧。至于為什么要這么去獲取,后面我們會說道。

拿到statementHandler后,我們會通過MetaObject MetaObjectHandler = SystemMetaObject.forObject(statementHandler);去獲取它的包裝對象,通過包裝對象去獲取各種服務(wù)。

MetaObject:mybatis的一個工具類,方便我們有效的讀取或修改一些重要對象的屬性。四大對象(ResultSetHandler,ParameterHandler,Executor和statementHandler)提供的公共方法很少,要想直接獲取里面屬性的值很困難,但是可以通過MetaObject利用一些技術(shù)(內(nèi)部反射實現(xiàn))很輕松的讀取或修改里面的數(shù)據(jù)。

接下來說說:MappedStatement mappedStatement = (MappedStatement) MetaObjectHandler.getValue("delegate.mappedStatement");

上面提到為什么要這么去獲取MappedStatement對象??在RoutingStatementHandler中delegate是私有的(private final StatementHandler delegate;),有沒有共有的方法去獲取。所以這里只有通過反射來獲取啦。

MappedStatement是保存了xxMapper.xml中一個sql語句節(jié)點的所有信息的包裝類,可以通過它獲取到節(jié)點中的所有信息。在示例中我們拿到了id值,也就是方法的名稱,通過名稱區(qū)攔截所有需要分頁的請求。

通過StatementHandler的包裝類,不光能拿到MappedStatement,還可以拿到下面的數(shù)據(jù):

    public abstract class BaseStatementHandler implements StatementHandler {
    protected final Configuration configuration;
    protected final ObjectFactory objectFactory;
    protected final TypeHandlerRegistry typeHandlerRegistry;
    protected final ResultSetHandler resultSetHandler;
    protected final ParameterHandler parameterHandler;
    protected final Executor executor;
    protected final MappedStatement mappedStatement;
    protected final RowBounds rowBounds;
    protected BoundSql boundSql;

    protected BaseStatementHandler(Executor executor, MappedStatement mappedStatement, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) {
        this.configuration = mappedStatement.getConfiguration();
        this.executor = executor;
        this.mappedStatement = mappedStatement;
        this.rowBounds = rowBounds;
        this.typeHandlerRegistry = this.configuration.getTypeHandlerRegistry();
        this.objectFactory = this.configuration.getObjectFactory();
        if(boundSql == null) {
            this.generateKeys(parameterObject);
            boundSql = mappedStatement.getBoundSql(parameterObject);
        }

        this.boundSql = boundSql;
        this.parameterHandler = this.configuration.newParameterHandler(mappedStatement, parameterObject, boundSql);
        this.resultSetHandler = this.configuration.newResultSetHandler(executor, mappedStatement, rowBounds, this.parameterHandler, resultHandler, boundSql);
    }

上面的所有數(shù)據(jù)都可以通過反射拿到。

幾個重要的參數(shù):

  • Configuration:所有配置的相關(guān)信息。

  • ResultSetHandler:用于攔截執(zhí)行結(jié)果的組裝。

  • ParameterHandler:攔截執(zhí)行Sql的參數(shù)的組裝。

  • Executor:執(zhí)行Sql的全過程,包括組裝參數(shù)、組裝結(jié)果和執(zhí)行Sql的過程。

  • BoundSql:執(zhí)行的Sql的相關(guān)信息。

接下來我們通過如下代碼拿到請求時的map對象(反射)。

 //獲取進(jìn)行數(shù)據(jù)庫操作時管理參數(shù)的handler
            ParameterHandler parameterHandler = (ParameterHandler) MetaObjectHandler.getValue("delegate.parameterHandler");
            //獲取請求時的參數(shù)
            Map<String, Object> paraObject = (Map<String, Object>) parameterHandler.getParameterObject();
            //也可以這樣獲取
            //paraObject = (Map<String, Object>) statementHandler.getBoundSql().getParameterObject();

拿到我們需要的currPage和pageSize參數(shù)后,就是組裝分頁查詢的sql語句’limitSql‘了。

最后通過MetaObjectHandler.setValue("delegate.boundSql.sql", limitSql);將原始的sql語句替換成我們新的分頁語句,完成偷天換日的功能,接下來讓代碼繼續(xù)執(zhí)行。

編寫好攔截器后,需要注冊到項目中,才能發(fā)揮它的作用。在mybatis的配置文件中,添加如下代碼:

    <plugins>
        <plugin interceptor="com.cbg.interceptor.MyPageInterceptor">
            <property name="limit" value="10"/>
            <property name="dbType" value="mysql"/>
        </plugin>
    </plugins>

如上所示,還能在里面配置一些屬性,在攔截器的setProperties方法中可以獲取配置好的屬性值。如項目分頁的pageSize參數(shù)的值固定,我們就可以配置在這里了,以后就不需要每次傳入pageSize了,讀取方式如下:

 //讀取配置的代理對象的參數(shù)
    @Override
    public void setProperties(Properties properties) {
        String limit1 = properties.getProperty("limit", "10");
        this.pageSize = Integer.valueOf(limit1);
        this.dbType = properties.getProperty("dbType", "mysql");
    }

到這里,有關(guān)攔截器的相關(guān)知識就講解的差不多了,接下來就需要測試,是否我們這樣寫真的有效??

首先還是添加dao層的方法和xml文件的sql語句配置,注意項目中攔截的是以ByPage結(jié)尾的請求,所以在這里,我們的方法名稱也以此結(jié)尾:

方法
List<Student> queryStudentsByPage(Map<String,Object> data);

xml文件的select語句
    <select id="queryStudentsByPage" parameterType="map" resultMap="studentmapper">
        select * from student
    </select>

可以看出,這里我們就不需要再去手動配置分頁語句了。

接下來是service層的接口編寫和實現(xiàn)方法:

方法:
List<Student> queryStudentsByPage(int currPage,int pageSize);

實現(xiàn):
 @Override
    public List<Student> queryStudentsByPage(int currPage, int pageSize) {
        Map<String, Object> data = new HashedMap();
        data.put("currPage", currPage);
        data.put("pageSize", pageSize);
        return studentMapper.queryStudentsByPage(data);
    }

這里我們雖然傳入了currPage和pageSize兩個參數(shù),但是在sql的xml文件中并沒有使用,直接在攔截器中獲取到統(tǒng)一使用。

最后編寫controller的測試代碼:

 @ResponseBody
    @RequestMapping("/student/page/{currPage}/{pageSize}")
    public List<Student> getStudentByPage(@PathVariable("currPage") int currPage, @PathVariable("pageSize") int pageSize) {
        List<Student> student = StuServiceIml.queryStudentsByPage(currPage, pageSize);
        return student;
    }

測試:

在瀏覽器輸入:http://localhost:8080/student/student/page/1/2

結(jié)果:

Plusieurs fa?ons de paginer dans mybatis
可見和上面兩種分頁的效果是一樣的。

4、RowBounds實現(xiàn)分頁

原理:通過RowBounds實現(xiàn)分頁和通過數(shù)組方式分頁原理差不多,都是一次獲取所有符合條件的數(shù)據(jù),然后在內(nèi)存中對大數(shù)據(jù)進(jìn)行操作,實現(xiàn)分頁效果。只是數(shù)組分頁需要我們自己去實現(xiàn)分頁邏輯,這里更加簡化而已。

存在問題:一次性從數(shù)據(jù)庫獲取的數(shù)據(jù)可能會很多,對內(nèi)存的消耗很大,可能導(dǎo)師性能變差,甚至引發(fā)內(nèi)存溢出。

適用場景:在數(shù)據(jù)量很大的情況下,建議還是適用攔截器實現(xiàn)分頁效果。RowBounds建議在數(shù)據(jù)量相對較小的情況下使用。

簡單介紹:這是代碼實現(xiàn)上最簡單的一種分頁方式,只需要在dao層接口中要實現(xiàn)分頁的方法中加入RowBounds參數(shù),然后在service層通過offset(從第幾行開始讀取數(shù)據(jù),默認(rèn)值為0)和limit(要顯示的記錄條數(shù),默認(rèn)為java允許的最大整數(shù):2147483647)兩個參數(shù)構(gòu)建出RowBounds對象,在調(diào)用dao層方法的時,將構(gòu)造好的RowBounds傳進(jìn)去就能輕松實現(xiàn)分頁效果了。

具體操作如下:

dao層接口方法:

//加入RowBounds參數(shù)
public List<UserBean> queryUsersByPage(String userName, RowBounds rowBounds);

然后在service層構(gòu)建RowBounds,調(diào)用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;
    }
}

只需要這兩步操作,就能輕松實現(xiàn)分頁效果了,是不是很神奇。但卻不簡單,內(nèi)部是怎么實現(xiàn)的??給大家提供一個簡單的思路:RowBounds分頁簡單原理

結(jié)論:從上面四種sql分頁的實現(xiàn)方式可以看出,通過RowBounds實現(xiàn)是最簡便的,但是通過攔截器的實現(xiàn)方式是最優(yōu)的方案。只需一次編寫,所有的分頁方法共同使用,還可以避免多次配置時的出錯機(jī)率,需要修改時也只需要修改這一個文件,一勞永逸。而且是我們自己實現(xiàn)的,便于我們?nèi)タ刂坪驮黾右恍┻壿嬏幚恚刮覀冊谕鈱痈唵蔚氖褂?。同時也不會出現(xiàn)數(shù)組分頁和RowBounds分頁導(dǎo)致的性能問題。當(dāng)然,具體情況可以采取不同的解決方案。數(shù)據(jù)量小時,RowBounds不失為一種好辦法。但是數(shù)據(jù)量大時,實現(xiàn)攔截器就很有必要了。

【相關(guān)推薦:編程教學(xué)

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration de ce site Web
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefa?on, veuillez contacter admin@php.cn

Outils d'IA chauds

Undress AI Tool

Undress AI Tool

Images de déshabillage gratuites

Undresser.AI Undress

Undresser.AI Undress

Application basée sur l'IA pour créer des photos de nu réalistes

AI Clothes Remover

AI Clothes Remover

Outil d'IA en ligne pour supprimer les vêtements des photos.

Clothoff.io

Clothoff.io

Dissolvant de vêtements AI

Video Face Swap

Video Face Swap

échangez les visages dans n'importe quelle vidéo sans effort grace à notre outil d'échange de visage AI entièrement gratuit?!

Article chaud

Outils chauds

Bloc-notes++7.3.1

Bloc-notes++7.3.1

éditeur de code facile à utiliser et gratuit

SublimeText3 version chinoise

SublimeText3 version chinoise

Version chinoise, très simple à utiliser

Envoyer Studio 13.0.1

Envoyer Studio 13.0.1

Puissant environnement de développement intégré PHP

Dreamweaver CS6

Dreamweaver CS6

Outils de développement Web visuel

SublimeText3 version Mac

SublimeText3 version Mac

Logiciel d'édition de code au niveau de Dieu (SublimeText3)

Sujets chauds

Tutoriel PHP
1502
276
iBatis vs MyBatis?: lequel vous convient le mieux?? iBatis vs MyBatis?: lequel vous convient le mieux?? Feb 19, 2024 pm 04:38 PM

iBatis vs MyBatis : lequel choisir ? Introduction : Avec le développement rapide du langage Java, de nombreux frameworks de persistance ont vu le jour. iBatis et MyBatis sont deux frameworks de persistance populaires, qui fournissent tous deux une solution d'accès aux données simple et efficace. Cet article présentera les fonctionnalités et les avantages d'iBatis et MyBatis, et donnera quelques exemples de code spécifiques pour vous aider à choisir le framework approprié. Introduction à iBatis?: iBatis est un framework de persistance open source

Analyse comparative des fonctions et performances de JPA et MyBatis Analyse comparative des fonctions et performances de JPA et MyBatis Feb 19, 2024 pm 05:43 PM

JPA et MyBatis?: analyse comparative des fonctions et des performances Introduction?: Dans le développement Java, le framework de persistance joue un r?le très important. Les frameworks de persistance courants incluent JPA (JavaPersistenceAPI) et MyBatis. Cet article procédera à une analyse comparative des fonctions et des performances des deux frameworks et fournira des exemples de code spécifiques. 1. Comparaison des fonctions : JPA : JPA fait partie de JavaEE et fournit une solution de persistance des données orientée objet. Il est passé une annotation ou X

Explication détaillée de la fonction Définir la balise dans les balises SQL dynamiques MyBatis Explication détaillée de la fonction Définir la balise dans les balises SQL dynamiques MyBatis Feb 26, 2024 pm 07:48 PM

Interprétation des balises SQL dynamiques MyBatis?: explication détaillée de l'utilisation des balises Set MyBatis est un excellent cadre de couche de persistance. Il fournit une multitude de balises SQL dynamiques et peut construire de manière flexible des instructions d'opération de base de données. Parmi elles, la balise Set est utilisée pour générer la clause SET dans l'instruction UPDATE, qui est très couramment utilisée dans les opérations de mise à jour. Cet article expliquera en détail l'utilisation de la balise Set dans MyBatis et démontrera ses fonctionnalités à travers des exemples de code spécifiques. Qu'est-ce que Set tag Set tag est utilisé dans MyBati

Différentes manières de mettre en ?uvre des opérations de suppression par lots dans MyBatis Différentes manières de mettre en ?uvre des opérations de suppression par lots dans MyBatis Feb 19, 2024 pm 07:31 PM

Plusieurs fa?ons d'implémenter des instructions de suppression par lots dans MyBatis nécessitent des exemples de code spécifiques. Ces dernières années, en raison de la quantité croissante de données, les opérations par lots sont devenues une partie importante des opérations de base de données. Dans le développement réel, nous devons souvent supprimer des enregistrements de la base de données par lots. Cet article se concentrera sur plusieurs fa?ons d'implémenter des instructions de suppression par lots dans MyBatis et fournira des exemples de code correspondants. Utilisez la balise foreach pour implémenter la suppression par lots. MyBatis fournit la balise foreach, qui peut facilement parcourir un ensemble.

Comparaison des similitudes et des différences entre iBatis et MyBatis?: comparaison des frameworks ORM traditionnels Comparaison des similitudes et des différences entre iBatis et MyBatis?: comparaison des frameworks ORM traditionnels Feb 19, 2024 pm 07:08 PM

iBatis et MyBatis sont deux frameworks ORM (Object-Relational Mapping) traditionnels. Ils présentent de nombreuses similitudes dans la conception et l'utilisation, mais présentent également quelques différences subtiles. Cet article comparera en détail les similitudes et les différences entre iBatis et MyBatis et illustrera leurs caractéristiques à travers des exemples de code spécifiques. 1. L'histoire et le contexte d'iBatis et MyBatis iBatis est Apache Software Foundat

Explication détaillée du mécanisme de cache MyBatis?: comprendre le principe du stockage en cache dans un article Explication détaillée du mécanisme de cache MyBatis?: comprendre le principe du stockage en cache dans un article Feb 23, 2024 pm 04:09 PM

Explication détaillée du mécanisme de mise en cache MyBatis?: Lisez le principe du stockage en cache dans un article Introduction Lorsque vous utilisez MyBatis pour l'accès à la base de données, la mise en cache est un mécanisme très important, qui peut réduire efficacement l'accès à la base de données et améliorer les performances du système. Cet article présentera en détail le mécanisme de mise en cache de MyBatis, y compris la classification du cache, les principes de stockage et des exemples de code spécifiques. 1. Classification du cache Le cache MyBatis est principalement divisé en deux types : le cache de premier niveau et le cache de deuxième niveau. Le cache de premier niveau est un cache de niveau SQLSession.

Interprétation des paramètres de configuration de MyBatis Generator et bonnes pratiques Interprétation des paramètres de configuration de MyBatis Generator et bonnes pratiques Feb 23, 2024 am 09:51 AM

MyBatisGenerator est un outil de génération de code officiellement fourni par MyBatis, qui peut aider les développeurs à générer rapidement des JavaBeans, des interfaces Mapper et des fichiers de mappage XML conformes à la structure des tables de base de données. Dans le processus d'utilisation de MyBatisGenerator pour la génération de code, la définition des paramètres de configuration est cruciale. Cet article commencera du point de vue des paramètres de configuration et explorera en profondeur les fonctions de MyBatisGenerator.

Compréhension approfondie du principe d'implémentation de l'insertion par lots dans MyBatis Compréhension approfondie du principe d'implémentation de l'insertion par lots dans MyBatis Feb 21, 2024 pm 04:42 PM

MyBatis est un framework de couche de persistance Java populaire qui est largement utilisé dans divers projets Java. Parmi elles, l'insertion par lots est une opération courante qui peut améliorer efficacement les performances des opérations de base de données. Cet article explorera en profondeur le principe de mise en ?uvre de l'insertion par lots dans MyBatis et l'analysera en détail avec des exemples de code spécifiques. Insertion par lots dans MyBatis Dans MyBatis, les opérations d'insertion par lots sont généralement implémentées à l'aide de SQL dynamique. En construisant un S contenant plusieurs valeurs insérées

See all articles