shardingJdbc3.x?版本的分頁bug問題解析
引言
shardingJdbc 改名為 shardingsphere ,同時項目也已經(jīng)畢業(yè)并成為 Apache 頂級項目,但是這是發(fā)現(xiàn)它的第二個重大 BUG,說明還是有很大的進步空間。
上次發(fā)現(xiàn)的重大 BUG :http://www.dbjr.com.cn/program/286235e92.htm
BUG 的表象是在使用 shardingJdbc3.1.0 進行分頁查詢的時候存在問題,一般情況下 sql 是這樣的格式 limit x,y
,但是不管怎么翻頁查詢,x 的值一直都是 0,這會導致查詢出來的結(jié)果,每一次翻頁的數(shù)據(jù)會越來越多,都包含了前一頁的數(shù)據(jù)。
首先,使用 shardingJdbc 的情況下,理論上就不應(yīng)該存在分頁查詢。 原因可以想象使用 shardingJdbc 是為了分表,既然是分表了那么這種查詢必然會通過條件查詢所有涉及到的表來得出結(jié)果,然后聚合到內(nèi)存來進行分頁,這會使得機器的壓力是巨大的。
所以如果不涉及到分表的情況下,不應(yīng)該是用 shardingJdbc,如果使用了分表就不應(yīng)該這樣搞分頁查詢。
前提條件是理想的情況下,但是在某些情況下,誤用了導致沒有分表策略的表使用了 shardingJdbc 來進行操作也是有可能的。
shardingJdbc3.1.0 在處理 sql 中含有 limit x,y
這種操作的時候會進行特殊處理。
類名: io.shardingsphere.core.routing.router.sharding.ParsingSQLRouter
格式化 SQL 和處理 limit 的操作
以下是截取的一段它的格式化 SQL 和處理 limit 的操作。
@Override public SQLRouteResult route(final String logicSQL, final List<Object> parameters, final SQLStatement sqlStatement) { ...... if (sqlStatement instanceof SelectStatement && null != ((SelectStatement) sqlStatement).getLimit()) { processLimit(parameters, (SelectStatement) sqlStatement); } ...... } private void processLimit(final List<Object> parameters, final SelectStatement selectStatement) { boolean isNeedFetchAll = (!selectStatement.getGroupByItems().isEmpty() || !selectStatement.getAggregationSelectItems().isEmpty()) && !selectStatement.isSameGroupByAndOrderByItems(); selectStatement.getLimit().processParameters(parameters, isNeedFetchAll, databaseType); }
其中 selectStatement.getLimit () 得到的 Limit 類的實現(xiàn)有點問題,這個導致了問題就很大了。
類名: io.shardingsphere.core.parsing.parser.context.limit.Limit
實現(xiàn)方法
以下是截取的一段它的實現(xiàn)方法
* @param parameters parameters * @param isFetchAll is fetch all data or not * @param databaseType database type */ public void processParameters(final List<Object> parameters, final boolean isFetchAll, final DatabaseType databaseType) { fill(parameters); rewrite(parameters, isFetchAll, databaseType); } private void fill(final List<Object> parameters) { int offset = 0; if (null != this.offset) { offset = -1 == this.offset.getIndex() ? getOffsetValue() : NumberUtil.roundHalfUp(parameters.get(this.offset.getIndex())); this.offset.setValue(offset); } int rowCount = 0; if (null != this.rowCount) { rowCount = -1 == this.rowCount.getIndex() ? getRowCountValue() : NumberUtil.roundHalfUp(parameters.get(this.rowCount.getIndex())); this.rowCount.setValue(rowCount); } if (offset < 0 || rowCount < 0) { throw new SQLParsingException("LIMIT offset and row count can not be a negative value."); } } private void rewrite(final List<Object> parameters, final boolean isFetchAll, final DatabaseType databaseType) { int rewriteOffset = 0; int rewriteRowCount; if (isFetchAll) { rewriteRowCount = Integer.MAX_VALUE; } else if (isNeedRewriteRowCount(databaseType)) { rewriteRowCount = null == rowCount ? -1 : getOffsetValue() + rowCount.getValue(); } else { rewriteRowCount = rowCount.getValue(); } if (null != offset && offset.getIndex() > -1) { parameters.set(offset.getIndex(), rewriteOffset); } if (null != rowCount && rowCount.getIndex() > -1) { parameters.set(rowCount.getIndex(), rewriteRowCount); } }
在對 limit 語法進行處理的時候,會重寫掉這個 offset,使得 offset=0,這就導致了每次向后翻頁操作的數(shù)據(jù)會把前一次的分頁查詢結(jié)果也帶上,每向后翻一頁就會還是從 0 開始讀取數(shù)據(jù)。
所以,解決方案就是如果不是分表就不要去用 shardingJdbc,如果是分表就不要去分頁查詢,性能損耗太嚴重,畢竟它得聚合到內(nèi)存之后再進行分頁處理,這個數(shù)據(jù)量過大的時候真的很容易出事。
如果一定要這么玩,那么看下 shardingJdbc 的新版本 4.x 是否修復了這個 BUG,聽說已經(jīng)修復了,沒去試過。
以上就是shardingJdbc3.x 版本的分頁問題解析的詳細內(nèi)容,更多關(guān)于shardingJdbc版本分頁的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
IDEA報錯:Process terminated的問題及解決
這篇文章主要介紹了IDEA報錯:Process terminated的問題及解決方案,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2023-11-11spring-boot中spring-boot-maven-plugin報紅錯誤及解決
這篇文章主要介紹了spring-boot中spring-boot-maven-plugin報紅錯誤及解決方案,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2023-03-03詳解java并發(fā)之重入鎖-ReentrantLock
這篇文章主要介紹了java并發(fā)之重入鎖-ReentrantLock,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2019-03-03Java創(chuàng)建數(shù)組的幾種方式總結(jié)
下面小編就為大家?guī)硪黄狫ava創(chuàng)建數(shù)組的幾種方式總結(jié)。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2016-10-10Springboot2以代碼的方式統(tǒng)一配置Jackson教程
這篇文章主要介紹了Springboot2以代碼的方式統(tǒng)一配置Jackson教程,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2021-11-11Java11中基于嵌套關(guān)系的訪問控制優(yōu)化詳解
Java(和其他語言)通過內(nèi)部類支持嵌套類,要使其正常工作,需要編譯器執(zhí)行一些技巧,下面這篇文章主要給大家介紹了關(guān)于Java11中基于嵌套關(guān)系的訪問控制優(yōu)化的相關(guān)資料,需要的朋友可以參考下2022-01-01