欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Mybatis邏輯分頁與物理分頁PageHelper使用解析

 更新時間:2023年12月20日 10:51:13   作者:原來是小袁吶  
這篇文章主要為大家介紹了Mybatis邏輯分頁與物理分頁PageHelper使用解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪

一、邏輯分頁

理解:數(shù)據(jù)庫一次性取出全部數(shù)據(jù)存儲到List集合中,再根據(jù)工具類獲取指定返回的數(shù)據(jù),如下是通過stream流實現(xiàn)

PageUtils

package com.example.segmentfaulttest0.utils;
import lombok.Data;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
/**
 * @description:分頁工具類
 * @author: 袁凱
 * @time: 2023/12/14 19:36
 */
@Data
public class PageUtils<E extends Serializable> implements Serializable {
    private static final long serialVersionUID = 1L;
    /**
     * 總記錄數(shù)
     */
    private int totalCount;
    /**
     * 每頁記錄數(shù)
     */
    private int pageSize;
    /**
     * 總頁數(shù)
     */
    private int totalPage;
    /**
     * 當(dāng)前頁數(shù)
     */
    private int currPage;
    /**
     * 列表數(shù)據(jù)
     */
    private List<E> list;
    /**
     *
     * @param pageSize  每頁記錄數(shù)
     * @param currPage  當(dāng)前頁數(shù)
     * @param totalList 總記錄列表
     */
    public PageUtils(int pageSize, int currPage, List<E> totalList) {
        this.totalCount = totalList.size();
        this.pageSize = pageSize;
        this.totalPage = (int) Math.ceil((double) totalCount / pageSize);
        this.currPage = currPage;
        this.list = this.currPage >= 1 ? totalList.stream().skip((long) (currPage - 1) * pageSize).limit(pageSize).collect(Collectors.toList()) : new ArrayList<>();
    }
}

二、物理分頁(PageHelper)

1.注意事項

①PageHelper的原理是通過攔截器實現(xiàn)的,他會先發(fā)送一個計數(shù)SQL語句,再使用limit進行查詢。比如在一對多的查詢中,我們有時候是根據(jù)主表進行分頁的,比如說主表有3條,從表有7條,這時候可能出現(xiàn)分頁total數(shù)量為7,這時候我們可以使用嵌套查詢代替聯(lián)表查詢使分頁結(jié)果準(zhǔn)確

②有時候我們需要將查詢出來的數(shù)據(jù)轉(zhuǎn)換為VO對象,但會出現(xiàn)total一直為List.size()的問題,而不是總數(shù)量,這是由于我們查出來的并不是ArrayList對象,而是Page對象,其中封裝了部分參數(shù),當(dāng)調(diào)用PageInfo的構(gòu)造方法時,他并不會進入正常的流程,為了解決這個問題,我們需要手動將total傳遞給新的PageInfo對象,如下

@GetMapping("/select")
    public TableDataInfo selectSelectiveLike() {
        startPage();
        List<Vrt> vrtList = vrtService.selectSelectiveLike(new Vrt());
        PageInfo<Vrt> pageInfo = new PageInfo<>(vrtList);
        List<VrtVo> vrtVos = new ArrayList<>();
        for (Vrt vrt : vrtList) {
            VrtVo vrtVo = new VrtVo();
            BeanUtils.copyProperties(vrt, vrtVo);
            List<VrtPhone> vrtPhoneList = vrt.getVrtPhoneList();
            if (vrtPhoneList != null && !vrtPhoneList.isEmpty()) {
                vrtVo.setNum(vrtPhoneList.size());
            } else {
                vrtVo.setNum(0);
            }
            vrtVos.add(vrtVo);
        }
        // 1.由于PageInfo中參數(shù)很多,有時候并不需要,因此自定義了一個TableDataInfo對象用于封裝參數(shù)
        // 2.我們在這里手動將PageInfo的值傳遞給VO的分頁對象即可
        TableDataInfo tableDataInfo = new TableDataInfo();
        tableDataInfo.setCode(HttpStatus.SUCCESS);
        tableDataInfo.setRows(vrtVos);
        tableDataInfo.setMsg("查詢成功");
        tableDataInfo.setTotal(pageInfo.getTotal());
        return tableDataInfo;
    }

2.mybatis簡要插件實現(xiàn)

插件類

package com.example.segmentfaulttest0.Interceptor;
import org.apache.ibatis.executor.Executor;
import org.apache.ibatis.executor.resultset.ResultSetHandler;
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.sql.Statement;
import java.util.Properties;
/**
 * @description:自定義插件,用于攔截mybatis的query方法
 * @author: 袁凱
 * @time: 2023/12/18 16:53
 */
//mybatis的攔截器注解以及簽名注解,用于需要攔截的類名,方法名,參數(shù)類型
@Intercepts({//注意看這個大花括號,也就這說這里可以定義多個@Signature對多個地方攔截,都用這個攔截器
    @Signature(type = Executor.class,
        method = "query",
        args = {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class})
})
//@Intercepts({
//    @Signature(
//        type = Executor.class,
//        method = "update",
//        args = {MappedStatement.class, Object.class}),
//})
public class MyPlugin implements Interceptor {
    public MyPlugin() {
        System.out.println("myplugin");
    }
    @Override
    public Object intercept(Invocation invocation) throws Throwable {
        //攔截成功,do something
        System.out.println("do something");
        return invocation.proceed();
    }
    @Override
    public Object plugin(Object target) {
        return Plugin.wrap(target, this);    //將被攔截對象生成代理對象
    }
    /**
     * 用于獲取pom.xml中property標(biāo)簽中寫入的屬性
     * @param properties
     */
    @Override
    public void setProperties(Properties properties) {
        Interceptor.super.setProperties(properties);
    }
}

配置類

package com.example.segmentfaulttest0.config;
import com.example.segmentfaulttest0.Interceptor.MyPlugin;
import org.apache.ibatis.session.SqlSessionFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.util.List;
/**
 * @description:Mybatis相關(guān)配置
 * @author: 袁凱
 * @time: 2023/12/18 17:39
 */
@Configuration
public class MybatisConfig {
    @Autowired
    private List<SqlSessionFactory> sqlSessionFactoryList;
    @Bean
    public void myPlugin() {
        for (SqlSessionFactory sqlSessionFactory : sqlSessionFactoryList) {
            org.apache.ibatis.session.Configuration configuration = sqlSessionFactory.getConfiguration();
            // 最后添加的會更早執(zhí)行
            configuration.addInterceptor(new MyPlugin());
        }
    }
}

mybatis可攔截的類

對象作用
StatementHandler(語句處理器)負(fù)責(zé)處理 SQL 語句的預(yù)編譯、參數(shù)設(shè)置等工作,其中最核心的工作是創(chuàng)建 JDBC 中的 Statement 對象,并為 SQL 語句綁定參數(shù)。
ParameterHandler(參數(shù)處理器)用于處理 SQL 語句中的參數(shù),負(fù)責(zé)為 SQL 語句中的參數(shù)設(shè)置值
Executor(執(zhí)行器)負(fù)責(zé)執(zhí)行由用戶發(fā)起的對數(shù)據(jù)庫的增刪改查操作
ResultSetHandler(結(jié)果集處理器)負(fù)責(zé)處理 SQL 執(zhí)行后的結(jié)果集,將結(jié)果集轉(zhuǎn)換成用戶需要的 Java 對象

3.PageInterceptor攔截器說明

頭部注解及相關(guān)對象作用

@Intercepts({@Signature(
    type = Executor.class,
    method = "query",
    args = {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class}
), @Signature(
    type = Executor.class,
    method = "query",
    args = {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class, CacheKey.class, BoundSql.class}
)})
public class PageInterceptor implements Interceptor {
表列 A表列 B
MappedStatement var1表示當(dāng)前執(zhí)行的SQL的映射配置信息,包括BoundSql對象
Object var2表示傳遞給SQL的參數(shù)對象,可以是單個參數(shù),也可以是一個Map或POJO
RowBounds var3用于控制結(jié)果集偏移量和限制數(shù)量,即分頁查詢時的偏移量和限制返回的行數(shù)
ResultHandler var4負(fù)責(zé)處理 SQL 執(zhí)行后的結(jié)果集,將結(jié)果集轉(zhuǎn)換成用戶需要的 Java 對象
CacheKey var5MyBatis的緩存機制中使用的緩存鍵,可以用于緩存查詢結(jié)果
BoundSql var6表示包含了SQL語句和對應(yīng)參數(shù)映射信息的BoundSql對象,可以用于訪問SQL語句及其參數(shù)

intercept方法源碼解析

public Object intercept(Invocation invocation) throws Throwable {
        try {
            // 1.根據(jù)重載的攔截query方法不同,獲取不同的對象以及緩存key
            Object[] args = invocation.getArgs();
            MappedStatement ms = (MappedStatement)args[0];
            Object parameter = args[1];
            RowBounds rowBounds = (RowBounds)args[2];
            ResultHandler resultHandler = (ResultHandler)args[3];
            Executor executor = (Executor)invocation.getTarget();
            CacheKey cacheKey;
            BoundSql boundSql;
            if (args.length == 4) {
                boundSql = ms.getBoundSql(parameter);
                cacheKey = executor.createCacheKey(ms, parameter, rowBounds, boundSql);
            } else {
                cacheKey = (CacheKey)args[4];
                boundSql = (BoundSql)args[5];
            }
            // 2.mybatis對不同的數(shù)據(jù)庫進行方言相關(guān)的檢查
            this.checkDialectExists();
            if (this.dialect instanceof BoundSqlInterceptor.Chain) {
                boundSql = ((BoundSqlInterceptor.Chain)this.dialect).doBoundSql(Type.ORIGINAL, boundSql, cacheKey);
            }
            List resultList;
            if (!this.dialect.skip(ms, parameter, rowBounds)) {
                this.debugStackTraceLog();
                if (this.dialect.beforeCount(ms, parameter, rowBounds)) {
                    // 3.執(zhí)行一條sql,select count(*) from xxx獲取總條數(shù)(根據(jù)原語句決定)
                    Long count = this.count(executor, ms, parameter, rowBounds, (ResultHandler)null, boundSql);
                    if (!this.dialect.afterCount(count, parameter, rowBounds)) {
                        Object var12 = this.dialect.afterPage(new ArrayList(), parameter, rowBounds);
                        return var12;
                    }
                }
                // 4.根據(jù)分頁參數(shù)執(zhí)行語句,在原語句的基礎(chǔ)上添加了limit ?,?
                resultList = ExecutorUtil.pageQuery(this.dialect, executor, ms, parameter, rowBounds, resultHandler, boundSql, cacheKey);
            } else {
                resultList = executor.query(ms, parameter, rowBounds, resultHandler, cacheKey, boundSql);
            }
            Object var16 = this.dialect.afterPage(resultList, parameter, rowBounds);
            return var16;
        } finally {
            if (this.dialect != null) {
                this.dialect.afterAll();
            }
        }
    }

PageHelper類中startPage(pageNum,pageSize)的作用

public static <E> Page<E> startPage(int pageNum, int pageSize, boolean count, Boolean reasonable, Boolean pageSizeZero) {
        Page<E> page = new Page(pageNum, pageSize, count);
        page.setReasonable(reasonable);
        page.setPageSizeZero(pageSizeZero);
        // 1.使用threadlocal進行線程存儲,為每個線程保存每個          分頁參數(shù)(當(dāng)前頁、頁數(shù))
        Page<E> oldPage = getLocalPage();
        if (oldPage != null && oldPage.isOrderByOnly()) {
            page.setOrderBy(oldPage.getOrderBy());
        }
        setLocalPage(page);
        return page;
    }

攔截器如何調(diào)用threadlocal里面的分頁參數(shù)

在上面的intercept方法第四點中,他會進入ExecutorUtil的方法

public static <E> List<E> pageQuery(Dialect dialect, Executor executor, MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql, CacheKey cacheKey) throws SQLException {
        if (!dialect.beforePage(ms, parameter, rowBounds)) {
            return executor.query(ms, parameter, RowBounds.DEFAULT, resultHandler, cacheKey, boundSql);
        } else {
            parameter = dialect.processParameterObject(ms, parameter, boundSql, cacheKey);
            String pageSql = dialect.getPageSql(ms, boundSql, parameter, rowBounds, cacheKey);
            BoundSql pageBoundSql = new BoundSql(ms.getConfiguration(), pageSql, boundSql.getParameterMappings(), parameter);
            Map<String, Object> additionalParameters = getAdditionalParameter(boundSql);
            Iterator var12 = additionalParameters.keySet().iterator();
            while(var12.hasNext()) {
                String key = (String)var12.next();
                pageBoundSql.setAdditionalParameter(key, additionalParameters.get(key));
            }
            if (dialect instanceof BoundSqlInterceptor.Chain) {
                // 1.他會再次調(diào)用PageHelper類里面的threadlocal,并獲取里面的分頁參數(shù)
                pageBoundSql = ((BoundSqlInterceptor.Chain)dialect).doBoundSql(Type.PAGE_SQL, pageBoundSql, cacheKey);
            }
            return executor.query(ms, parameter, RowBounds.DEFAULT, resultHandler, cacheKey, pageBoundSql);
        }
    }
// 回到pageHelper類中,他會將分頁參數(shù)封裝成Page對象,再放入threadlocal中
   public BoundSql doBoundSql(BoundSqlInterceptor.Type type, BoundSql boundSql, CacheKey cacheKey) {
        Page<Object> localPage = getLocalPage();
        BoundSqlInterceptor.Chain chain = localPage != null ? localPage.getChain() : null;
        if (chain == null) {
            BoundSqlInterceptor boundSqlInterceptor = localPage != null ? localPage.getBoundSqlInterceptor() : null;
            BoundSqlInterceptor.Chain defaultChain = this.pageBoundSqlInterceptors != null ? this.pageBoundSqlInterceptors.getChain() : null;
            if (boundSqlInterceptor != null) {
                chain = new BoundSqlInterceptorChain(defaultChain, Arrays.asList(boundSqlInterceptor));
            } else if (defaultChain != null) {
                chain = defaultChain;
            }

            if (chain == null) {
                chain = DO_NOTHING;
            }

            if (localPage != null) {
                localPage.setChain((BoundSqlInterceptor.Chain)chain);
            }
        }

        return ((BoundSqlInterceptor.Chain)chain).doBoundSql(type, boundSql, cacheKey);
    }

Page對象(實際上返回的對象)與PageInfo對象(我們最終使用的對象)

//1.集成了ArrayList類,用于封裝分頁信息以及封裝查詢出來的結(jié)果
public class Page<E> extends ArrayList<E>
//1.根據(jù)傳入的Page對象,獲取其中的參數(shù),如total
public class PageInfo<T> extends PageSerializable<T> {

總結(jié)流程

PageHelper開啟分頁->將分頁參數(shù)封裝到Page對象中,使用threadlocal存儲->PageInterceptor攔截器對方法進行一次攔截(清除threadlocal里面的分頁參數(shù))->在攔截器中,分別使用兩條SQL語句獲取total以及分頁后的數(shù)據(jù)(count和limit),并將信息封裝給Page對象->新建PageInfo對象,將Page對象傳入,PageInfo對象里面就包含了分頁數(shù)據(jù)及參數(shù)

以上就是Mybatis邏輯分頁與物理分頁PageHelper使用解析的詳細內(nèi)容,更多關(guān)于Mybatis PageHelper分頁的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • 基于Spring boot @Value 注解注入屬性值的操作方法

    基于Spring boot @Value 注解注入屬性值的操作方法

    這篇文章主要介紹了結(jié)合SpEL使用@Value-基于配置文件或非配置的文件的值注入-Spring Boot的相關(guān)知識,本文通過實例代碼給大家介紹的非常詳細,對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2020-07-07
  • SpringSecurity中的Filter Chain(過濾器鏈)

    SpringSecurity中的Filter Chain(過濾器鏈)

    Spring Security的Filter Chain是由一系列過濾器組成的管道,每個過濾器執(zhí)行特定的安全功能,Spring Security能夠提供強大而靈活的安全控制機制,從而保護你的應(yīng)用程序不受各種網(wǎng)絡(luò)安全威脅的侵害,本文介紹SpringSecurity中的Filter Chain,感興趣的朋友跟隨小編一起看看吧
    2024-06-06
  • ActiveMQ結(jié)合Spring收發(fā)消息的示例代碼

    ActiveMQ結(jié)合Spring收發(fā)消息的示例代碼

    這篇文章主要介紹了ActiveMQ結(jié)合Spring收發(fā)消息的示例代碼,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2018-10-10
  • Java迭代器與Collection接口超詳細講解

    Java迭代器與Collection接口超詳細講解

    Collection也稱集合,集合概述:集合是Java中提供的一種容器,可以用來存儲多個數(shù)據(jù)。Iterator(迭代器)不是一個集合,它是一種用于訪問集合的方法,可用于迭代 ArrayList 和 HashSet 等集合
    2022-07-07
  • Java中final與繼承操作實例分析

    Java中final與繼承操作實例分析

    這篇文章主要介紹了Java中final與繼承操作,結(jié)合實例形式分析了Java中使用final阻止繼承的相關(guān)原理與操作注意事項,需要的朋友可以參考下
    2019-09-09
  • java?executor包參數(shù)處理功能?

    java?executor包參數(shù)處理功能?

    這篇文章主要介紹了java?executor包參數(shù)處理功能,sql語句中的參數(shù)賦值是有由executor包中的parameter子包完成的。parameter子包其實只有一個parameterHandler接口并且它定義了兩個方法,下面我們就來看詳細內(nèi)容吧,需要的朋友可以參考一下
    2022-02-02
  • Java使用JSON實現(xiàn)處理中文亂碼和Date格式

    Java使用JSON實現(xiàn)處理中文亂碼和Date格式

    這篇文章主要為大家詳細介紹了Java如何在項目中使用JSON實現(xiàn)處理中文亂碼和Date格式的功能,文中的示例代碼講解詳細,需要的小伙伴可以參考一下
    2023-06-06
  • java操作Apache druid的實例代碼

    java操作Apache druid的實例代碼

    這篇文章主要介紹了java操作Apache druid的實例代碼,本文通過實例代碼給大家介紹的非常詳細,對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2020-11-11
  • Java中Date時間類的使用方法舉例

    Java中Date時間類的使用方法舉例

    這篇文章主要給大家介紹了關(guān)于Java中Date時間類的使用方法,在java開發(fā)中,很多字段是Date類型的,文中通過代碼示例將Date時間類使用的方法介紹的非常詳細,需要的朋友可以參考下
    2023-08-08
  • mybatis的Configuration詳解

    mybatis的Configuration詳解

    這篇文章主要介紹了mybatis的Configuration詳解,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-11-11

最新評論