电脑知识|欧美黑人一区二区三区|软件|欧美黑人一级爽快片淫片高清|系统|欧美黑人狂野猛交老妇|数据库|服务器|编程开发|网络运营|知识问答|技术教程文章 - 好吧啦网

您的位置:首頁技術文章
文章詳情頁

SpringBoot使用 druid 連接池來優化分頁語句

瀏覽:6日期:2023-04-11 13:08:36

一、前言

一個老系統隨著數據量越來越大,我們察覺到部分分頁語句拖慢了我們的速度。

鑒于老系統的使用方式,不打算使用pagehelper和mybatis-plus來處理,加上系統里使用得是druid連接池,考慮直接使用druid來優化。

二、老代碼

老代碼是使用得一個mybatis插件進行的分頁,分頁的核心代碼如下:

// 記錄統計的 sqlString 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 外面包裝了一個 count sql,當然很多插件都是這樣做的。

三、druid 的 PagerUtil

示例 sql(有比較復雜的坐標計算)

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.compaddressFROM t_bas_integral_goods g LEFT JOIN t_bas_agent t ON g.agentid = t.AGENTIDWHERE t.AGENTTYPE = ’2’ AND t.pass = ’0’ AND t.dl_type = ’4’ AND g.type = 0ORDER 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.AGENTIDWHERE t.AGENTTYPE = ’2’ AND t.pass = ’0’ AND t.dl_type = ’4’ AND g.type = 0

我們可以看到優化后的 count sql 變得十分簡潔,坐標計算的都已經丟棄掉。 注意:PagerUtil還有limit方法用來生成limit語句,感興趣的同學可以自行試驗。

四、改造mybatis分頁插件

4.1 踩坑之路

看到上面 druid PagerUtils count 的優化效果,立馬開始改造起來,起初只改掉了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);

啟動起來測試一番就發現報錯了,因為原始 sql 中含有?變量,優化后的 sql 已經沒有變量了,插件還會繼續給他設置變量。 我們要怎么解決這個問題呢?

我們再回頭看看pagehelper和mybatis-plus是怎么實現的!它倆都是基于jsqlparser對 sql 進行解析,然后處理。

要多加一個jsqlparser?沒必要沒必要,druid 的 sql 解析功能也是很強大的,我看了看PagerUtils.count方法的源碼,大不了用 druid 的 sql 解析實現一遍。

看了看源碼之后我陷入了沉思,有必要搞這么復雜么?有沒有更好的方法?我反復 debug 發現了,DynamicSqlSource中有帶#{xxx}這樣的原始 sql,

那么我是否可以使用 druid 先對這種 mybatis 占位符的 sql 進行優化呢?我們來試試:

示例 sql:

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

輸出:

SELECT COUNT(*)FROM xxxWHERE type = #{type}

完美!!! 4.2 繼續踩坑

然而直接在 Mapper 上注解的 sql 還是有問題,拿不到原始的 sql,debug 發現 RawSqlSource 在構造器里就將 sql 處理成了?號掛參的形式。

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

那么我只能看看能不能擴展它,我找到了它是在XMLLanguageDriver里進行初始化,這下好辦了,因為我之前擴展過XMLLanguageDriver,它是可以自定義配置的。 于是我重寫了RawSqlSource, 添加上了包含 mybatis 參數占位符(#{})的rawSql字段。

/** * 原始 sql,用于方便 druid 工具進行分頁 * * @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<>()); } // ... ...}

自此全部邏輯已經走通,我們再來看看我們的PagePlugin核心代碼:

// 進行分頁Configuration configuration = mappedStatement.getConfiguration();SqlSourceBuilder sqlSourceParser = new SqlSourceBuilder(configuration);Class<?> parameterType = parameterObject.getClass();Connection connection = (Connection) invocation.getArgs()[0];// 1. 對 sql 進行判斷,如果沒有 ? 號,則直接處理String boundRawSql = boundSql.getSql();if (boundRawSql.indexOf(CharPool.QUESTION_MARK) == -1) { // 不包含 ? 號 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); // 將分頁sql語句反射回BoundSql. setField(boundSql, 'sql', pageSql); return invocation.proceed();}// 2. 按 SqlSource 進行解析SqlSource sqlSource = mappedStatement.getSqlSource();// xml 中的動態 sqlint 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 分頁形式,請使用 xml 或者注解');}

五、結論

整個老服務通過切換到 mica(深度定制)的微服務架構(演示環境僅僅在單服務低內存配置)之后速度提升效果明顯,當然后面我們還會繼續進行優化。

到此這篇關于SpringBoot使用 druid 連接池來優化分頁語句的文章就介紹到這了,更多相關SpringBoot druid 連接池分頁內容請搜索好吧啦網以前的文章或繼續瀏覽下面的相關文章希望大家以后多多支持好吧啦網!

標簽: Spring
相關文章:
主站蜘蛛池模板: 华中线缆有限公司-电缆厂|电缆厂家|电线电缆厂家 | 二手光谱仪维修-德国OBLF光谱仪|进口斯派克光谱仪-热电ARL光谱仪-意大利GNR光谱仪-永晖检测 | 喷码机,激光喷码打码机,鸡蛋打码机,手持打码机,自动喷码机,一物一码防伪溯源-恒欣瑞达有限公司 | 油缸定制-液压油缸厂家-无锡大鸿液压气动成套有限公司 | 东莞压铸厂_精密压铸_锌合金压铸_铝合金压铸_压铸件加工_东莞祥宇金属制品 | 臭氧老化试验箱,高低温试验箱,恒温恒湿试验箱,防水试验设备-苏州亚诺天下仪器有限公司 | 鼓风干燥箱_真空烘箱_高温干燥箱_恒温培养箱-上海笃特科学仪器 | 旋转/数显粘度计-运动粘度测定仪-上海平轩科学仪器 | 活性炭-蜂窝-椰壳-柱状-粉状活性炭-河南唐达净水材料有限公司 | 接地电阻测试仪[厂家直销]_电缆故障测试仪[精准定位]_耐压测试仪-武汉南电至诚电力设备 | 选矿设备,选矿生产线,选矿工艺,选矿技术-昆明昆重矿山机械 | 无缝方管|无缝矩形管|无缝方矩管|无锡方管厂家 | 智慧养老_居家养老_社区养老_杰佳通 | 泉州陶瓷pc砖_园林景观砖厂家_石英砖地铺石价格 _福建暴风石英砖 | 颚式破碎机,圆锥破碎机,制砂机-新乡市德诚机电制造有限公司 | 免费分销系统 — 分销商城系统_分销小程序开发 -【微商来】 | 无线对讲-无线对讲系统解决方案-重庆畅博通信 | 换链神器官网-友情链接交换、购买交易于一体的站长平台 | 无线遥控更衣吊篮_IC卡更衣吊篮_电动更衣吊篮配件_煤矿更衣吊篮-力得电子 | 定量包装机,颗粒定量包装机,粉剂定量包装机,背封颗粒包装机,定量灌装机-上海铸衡电子科技有限公司 | AGV叉车|无人叉车|AGV智能叉车|AGV搬运车-江西丹巴赫机器人股份有限公司 | 绿叶|绿叶投资|健康产业_绿叶投资集团有限公司 | 温州中研白癜风专科_温州治疗白癜风_温州治疗白癜风医院哪家好_温州哪里治疗白癜风 | 玉米加工设备,玉米深加工机械,玉米糁加工设备.玉米脱皮制糁机 华豫万通粮机 | 超声波清洗机-超声波清洗设备定制生产厂家 - 深圳市冠博科技实业有限公司 | 西安文都考研官网_西安考研辅导班_考研培训机构_西安在职考研培训 | 深圳湾1号房价_深圳湾1号二手房源 | 切铝机-数控切割机-型材切割机-铝型材切割机-【昆山邓氏精密机械有限公司】 | 天然鹅卵石滤料厂家-锰砂滤料-石英砂滤料-巩义东枫净水 | 石家庄装修设计_室内家装设计_别墅装饰装修公司-石家庄金舍装饰官网 | 便民信息网_家电维修,家电清洗,开锁换锁,本地家政公司 | 气体热式流量计-定量控制流量计(空气流量计厂家)-湖北南控仪表科技有限公司 | ptc_浴霸_大巴_干衣机_呼吸机_毛巾架_电动车加热器-上海帕克 | 纯水电导率测定仪-万用气体检测仪-低钠测定仪-米沃奇科技(北京)有限公司www.milwaukeeinst.cn 锂辉石检测仪器,水泥成分快速分析仪-湘潭宇科分析仪器有限公司 手术室净化装修-手术室净化工程公司-华锐手术室净化厂家 | 涡轮流量计_LWGY智能气体液体电池供电计量表-金湖凯铭仪表有限公司 | 塑料熔指仪-塑料熔融指数仪-熔体流动速率试验机-广东宏拓仪器科技有限公司 | 地磅-地秤-江阴/无锡地磅-江阴天亿计量设备有限公司_ | 玖容气动液压设备有限公司-气液增压缸_压力机_增压机_铆接机_增压器 | 硫酸亚铁-聚合硫酸铁-除氟除磷剂-复合碳源-污水处理药剂厂家—长隆科技 | 北京公积金代办/租房发票/租房备案-北京金鼎源公积金提取服务中心 | 意大利Frascold/富士豪压缩机_富士豪半封闭压缩机_富士豪活塞压缩机_富士豪螺杆压缩机 |