亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

SpringBoot使用 druid 連接池來(lái)優(yōu)化分頁(yè)語(yǔ)句

 更新時(shí)間:2020年11月06日 09:48:24   作者:如夢(mèng)技術(shù)  
這篇文章主要介紹了SpringBoot使用 druid 連接池來(lái)優(yōu)化分頁(yè)語(yǔ)句,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧

一、前言

一個(gè)老系統(tǒng)隨著數(shù)據(jù)量越來(lái)越大,我們察覺(jué)到部分分頁(yè)語(yǔ)句拖慢了我們的速度。

鑒于老系統(tǒng)的使用方式,不打算使用pagehelper和mybatis-plus來(lái)處理,加上系統(tǒng)里使用得是druid連接池,考慮直接使用druid來(lái)優(yōu)化。

二、老代碼

老代碼是使用得一個(gè)mybatis插件進(jìn)行的分頁(yè),分頁(yè)的核心代碼如下:

// 記錄統(tǒng)計(jì)的 sql
String countSql = "select count(0) from (" + sql+ ") tmp_count";
PreparedStatement countStmt = connection.prepareStatement(countSql);
BoundSql countBS = new BoundSql(mappedStatement.getConfiguration(), countSql, boundSql.getParameterMappings(), parameterObject);
setParameters(countStmt, mappedStatement, countBS,parameterObject);

在原始的 sql 外面包裝了一個(gè) count sql,當(dāng)然很多插件都是這樣做的。

三、druid 的 PagerUtil

示例 sql(有比較復(fù)雜的坐標(biāo)計(jì)算)

SELECT g.*
  , ROUND(6378.138 * 2 * ASIN(SQRT(POW(SIN((? * PI() / 180 - t.latitude * PI() / 180) / 2), 2) + COS(? * PI() / 180) * COS(t.latitude * PI() / 180) * POW(SIN((? * PI() / 180 - t.longitude * PI() / 180) / 2), 2))), 2) AS distancecd
  , t.agentname, t.agentlogo, t.compaddress
FROM t_bas_integral_goods g
  LEFT JOIN t_bas_agent t ON g.agentid = t.AGENTID
WHERE t.AGENTTYPE = '2'
  AND t.pass = '0'
  AND t.dl_type = '4'
  AND g.type = 0
ORDER BY distancecd ASC

使用 Druid 生成 count sql:

String countSql = PagerUtils.count(sql, DbType.mysql);
System.out.println(countSql);

輸出:

SELECT COUNT(*)
FROM t_bas_integral_goods g
 LEFT JOIN t_bas_agent t ON g.agentid = t.AGENTID
WHERE t.AGENTTYPE = '2'
 AND t.pass = '0'
 AND t.dl_type = '4'
 AND g.type = 0

我們可以看到優(yōu)化后的 count sql 變得十分簡(jiǎn)潔,坐標(biāo)計(jì)算的都已經(jīng)丟棄掉。 注意:PagerUtil還有l(wèi)imit方法用來(lái)生成limit語(yǔ)句,感興趣的同學(xué)可以自行試驗(yàn)。

四、改造mybatis分頁(yè)插件

4.1 踩坑之路

看到上面 druid PagerUtils count 的優(yōu)化效果,立馬開(kāi)始改造起來(lái),起初只改掉了countSql,

String countSql = PagerUtils.count(sql, dbType);
PreparedStatement countStmt = connection.prepareStatement(countSql);
BoundSql countBS = new BoundSql(mappedStatement.getConfiguration(), countSql, boundSql.getParameterMappings(), parameterObject);
setParameters(countStmt, mappedStatement, countBS,parameterObject);

啟動(dòng)起來(lái)測(cè)試一番就發(fā)現(xiàn)報(bào)錯(cuò)了,因?yàn)樵?sql 中含有?變量,優(yōu)化后的 sql 已經(jīng)沒(méi)有變量了,插件還會(huì)繼續(xù)給他設(shè)置變量。 我們要怎么解決這個(gè)問(wèn)題呢?

我們?cè)倩仡^看看pagehelper和mybatis-plus是怎么實(shí)現(xiàn)的!它倆都是基于jsqlparser對(duì) sql 進(jìn)行解析,然后處理。

要多加一個(gè)jsqlparser?沒(méi)必要沒(méi)必要,druid 的 sql 解析功能也是很強(qiáng)大的,我看了看PagerUtils.count方法的源碼,大不了用 druid 的 sql 解析實(shí)現(xiàn)一遍。

看了看源碼之后我陷入了沉思,有必要搞這么復(fù)雜么?有沒(méi)有更好的方法?我反復(fù) debug 發(fā)現(xiàn)了,DynamicSqlSource中有帶#{xxx}這樣的原始 sql,

那么我是否可以使用 druid 先對(duì)這種 mybatis 占位符的 sql 進(jìn)行優(yōu)化呢?我們來(lái)試試:

示例 sql:

select * from xxx where type = #{type} order by xx

輸出:

SELECT COUNT(*)
FROM xxx
WHERE type = #{type}

完美!??! 4.2 繼續(xù)踩坑

然而直接在 Mapper 上注解的 sql 還是有問(wèn)題,拿不到原始的 sql,debug 發(fā)現(xiàn) RawSqlSource 在構(gòu)造器里就將 sql 處理成了?號(hào)掛參的形式。

@Select("select * from xxx where type = #{type} order by xx")
Object test(@Param("type") String type);

那么我只能看看能不能擴(kuò)展它,我找到了它是在XMLLanguageDriver里進(jìn)行初始化,這下好辦了,因?yàn)槲抑皵U(kuò)展過(guò)XMLLanguageDriver,它是可以自定義配置的。 于是我重寫(xiě)了RawSqlSource, 添加上了包含 mybatis 參數(shù)占位符(#{})的rawSql字段。

/**
 * 原始 sql,用于方便 druid 工具進(jìn)行分頁(yè)
 *
 * @author L.cm
 */
public class MicaRawSqlSource implements SqlSource {
  private final String rawSql;
  private final SqlSource sqlSource;
  public MicaRawSqlSource(Configuration configuration, SqlNode rootSqlNode, Class<?> parameterType) {
    this(configuration, getSql(configuration, rootSqlNode), parameterType);
  }
  public MicaRawSqlSource(Configuration configuration, String sql, Class<?> parameterType) {
    SqlSourceBuilder sqlSourceParser = new SqlSourceBuilder(configuration);
    Class<?> clazz = parameterType == null ? Object.class : parameterType;
    this.rawSql = sql;
    this.sqlSource = sqlSourceParser.parse(sql, clazz, new HashMap<>());
  }
  // ... ...
}

自此全部邏輯已經(jīng)走通,我們?cè)賮?lái)看看我們的PagePlugin核心代碼:

// 進(jìn)行分頁(yè)
Configuration configuration = mappedStatement.getConfiguration();
SqlSourceBuilder sqlSourceParser = new SqlSourceBuilder(configuration);
Class<?> parameterType = parameterObject.getClass();
Connection connection = (Connection) invocation.getArgs()[0];
// 1. 對(duì) sql 進(jìn)行判斷,如果沒(méi)有 ? 號(hào),則直接處理
String boundRawSql = boundSql.getSql();
if (boundRawSql.indexOf(CharPool.QUESTION_MARK) == -1) {
  // 不包含 ? 號(hào)
  String countSql = PagerUtils.count(boundRawSql, dbType);
  SqlSource newSqlSource = sqlSourceParser.parse(countSql, parameterType, new HashMap<>());
  BoundSql newBoundSql = newSqlSource.getBoundSql(parameterObject);
  int count = getCount(connection, mappedStatement, parameterObject, newBoundSql);
  StringBuilder sqlBuilder = new StringBuilder(boundRawSql);
  Page page = getPageParam(parameterObject, sqlBuilder, count);
  String pageSql = generatePageSql(sqlBuilder.toString(), dbType, page);
  // 將分頁(yè)sql語(yǔ)句反射回BoundSql.
  setField(boundSql, "sql", pageSql);
  return invocation.proceed();
}
// 2. 按 SqlSource 進(jìn)行解析
SqlSource sqlSource = mappedStatement.getSqlSource();
// xml 中的動(dòng)態(tài) sql
int count;
if (sqlSource instanceof DynamicSqlSource) {
  SqlNode rootSqlNode = PagePlugin.getField(sqlSource, "rootSqlNode");
  DynamicContext context = new DynamicContext(configuration, parameterObject);
  rootSqlNode.apply(context);
  // 生成 count sql,帶 #{xxx} 變量的 sql
  String countSql = PagerUtils.count(context.getSql(), dbType);
  SqlSource newSqlSource = sqlSourceParser.parse(countSql, parameterType, context.getBindings());
  BoundSql newBoundSql = newSqlSource.getBoundSql(parameterObject);
  count = getCount(connection, mappedStatement, parameterObject, newBoundSql);
} else if (sqlSource instanceof MicaRawSqlSource) {
  String rawSql = ((MicaRawSqlSource) sqlSource).getRawSql();
  DynamicContext context = new DynamicContext(configuration, parameterObject);
  // 生成 count sql,帶 #{xxx} 變量的 sql
  String countSql = PagerUtils.count(rawSql, dbType);
  SqlSource newSqlSource = sqlSourceParser.parse(countSql, parameterType, context.getBindings());
  BoundSql newBoundSql = newSqlSource.getBoundSql(parameterObject);
  count = getCount(connection, mappedStatement, parameterObject, newBoundSql);
} else {
  throw new IllegalArgumentException("不支持的 sql 分頁(yè)形式,請(qǐng)使用 xml 或者注解");
}

五、結(jié)論

整個(gè)老服務(wù)通過(guò)切換到 mica(深度定制)的微服務(wù)架構(gòu)(演示環(huán)境僅僅在單服務(wù)低內(nèi)存配置)之后速度提升效果明顯,當(dāng)然后面我們還會(huì)繼續(xù)進(jìn)行優(yōu)化。

到此這篇關(guān)于SpringBoot使用 druid 連接池來(lái)優(yōu)化分頁(yè)語(yǔ)句的文章就介紹到這了,更多相關(guān)SpringBoot druid 連接池分頁(yè)內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • string類(lèi)和LocalDateTime的相互轉(zhuǎn)換方式

    string類(lèi)和LocalDateTime的相互轉(zhuǎn)換方式

    這篇文章主要介紹了string類(lèi)和LocalDateTime的相互轉(zhuǎn)換方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-02-02
  • 如何將應(yīng)用的log4j替換成logback詳解

    如何將應(yīng)用的log4j替換成logback詳解

    無(wú)論從設(shè)計(jì)上還是實(shí)現(xiàn)上,Logback相對(duì)log4j而言有了相對(duì)多的改進(jìn)。所以下面這篇文章主要給大家介紹了關(guān)于如何將應(yīng)用的log4j換成logback的相關(guān)資料,文中介紹的很詳細(xì),需要的朋友可以參考下。
    2017-02-02
  • Java內(nèi)部類(lèi)及其特點(diǎn)的講解

    Java內(nèi)部類(lèi)及其特點(diǎn)的講解

    今天小編就為大家分享一篇關(guān)于Java內(nèi)部類(lèi)及其特點(diǎn)的講解,小編覺(jué)得內(nèi)容挺不錯(cuò)的,現(xiàn)在分享給大家,具有很好的參考價(jià)值,需要的朋友一起跟隨小編來(lái)看看吧
    2019-01-01
  • Netty分布式ByteBuf使用subPage級(jí)別內(nèi)存分配剖析

    Netty分布式ByteBuf使用subPage級(jí)別內(nèi)存分配剖析

    這篇文章主要為大家介紹了Netty分布式ByteBuf使用subPage級(jí)別內(nèi)存分配剖析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-03-03
  • IDEA如何一鍵部署SpringBoot項(xiàng)目到服務(wù)器

    IDEA如何一鍵部署SpringBoot項(xiàng)目到服務(wù)器

    文章介紹了如何在IDEA中部署SpringBoot項(xiàng)目到服務(wù)器,使用AlibabaCloudToolkit插件進(jìn)行配置部署,步驟包括設(shè)置服務(wù)名稱(chēng)、選擇文件上傳類(lèi)型、選擇jar文件、添加服務(wù)器信息、輸入上傳路徑、選擇上傳后執(zhí)行的腳本以及執(zhí)行前的操作命令
    2024-12-12
  • Java系統(tǒng)中拆分同步和異步詳解

    Java系統(tǒng)中拆分同步和異步詳解

    這篇文章主要給大家介紹了關(guān)于Java系統(tǒng)中拆分同步和異步的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家學(xué)習(xí)或者使用Java具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2019-06-06
  • JavaWeb三大組件之Filter過(guò)濾器詳解

    JavaWeb三大組件之Filter過(guò)濾器詳解

    這篇文章主要介紹了JavaWeb三大組件之Filter過(guò)濾器詳解,過(guò)濾器Filter是Java?Web應(yīng)用中的一種組件,它在請(qǐng)求到達(dá)Servlet或JSP之前或者響應(yīng)送回客戶(hù)端之前,對(duì)請(qǐng)求和響應(yīng)進(jìn)行預(yù)處理和后處理操作,需要的朋友可以參考下
    2023-10-10
  • IntelliJ IDEA創(chuàng)建普通的Java 項(xiàng)目及創(chuàng)建 Java 文件并運(yùn)行的教程

    IntelliJ IDEA創(chuàng)建普通的Java 項(xiàng)目及創(chuàng)建 Java 文件并運(yùn)行的教程

    這篇文章主要介紹了IntelliJ IDEA創(chuàng)建普通的Java 項(xiàng)目及創(chuàng)建 Java 文件并運(yùn)行的教程,本文通過(guò)圖文并茂的形式給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2021-02-02
  • Java實(shí)現(xiàn)輸入流轉(zhuǎn)化為String

    Java實(shí)現(xiàn)輸入流轉(zhuǎn)化為String

    這篇文章主要介紹了Java實(shí)現(xiàn)輸入流轉(zhuǎn)化為String的相關(guān)資料,需要的朋友可以參考下
    2016-12-12
  • Spring事務(wù)失效的場(chǎng)景梳理總結(jié)

    Spring事務(wù)失效的場(chǎng)景梳理總結(jié)

    實(shí)際項(xiàng)目開(kāi)發(fā)中,如果涉及到多張表操作時(shí),為了保證業(yè)務(wù)數(shù)據(jù)的一致性,大家一般都會(huì)采用事務(wù)機(jī)制,好多小伙伴可能只是簡(jiǎn)單了解一下,遇到事務(wù)失效的情況,便會(huì)無(wú)從下手,下面這篇文章主要給大家介紹了關(guān)于Spring事務(wù)失效場(chǎng)景的相關(guān)資料,需要的朋友可以參考下
    2023-02-02

最新評(píng)論