mybatisplus的分页查询很好用,当然大部分人分页后查询也没有问题,因为使用mybatis的构造器分页并且排序不会出现各种各样的问题,sql自动的帮你生成了。
但是当我们需要查询多张表时或者查询sql复杂的情况下,我们或许需要自己写sql,然后调用Page来实现分页。
唔姆,到这里都没有问题。
Page<持久层实体> queryPage =
queryRepository.selectPageVo(new Page<持久层实体>(当前页, 页长度), 查询条件);
正常流程下,mybatis会进行总数,页数等等的查询,返回返回total,size,current和record。
问题来了,进行count查询的时候,mybatis会在我们的自定义sql外嵌套total查询。如果我们在自定义sql里写了排序,order by的话,sqlserver就一定会报错,因为相当于是在子查询里排序了种种啥的。
然而大伙几乎都没有遇到这种情况,大部分都是使用构造器进行简单的sql查询分页排序。
为了解决需求,只有看看源码有没有提供了。幸运的是,Page源码里有关于排序的方法,addOrder,赶紧用起来试试,这一次,我们sql里就不添加order by语句了,让分页自己去排序。
Page<持久层实体> queryPage =
queryRepository.selectPageVo(new Page<持久层实体>(当前页, 页长度)
.addOrder(OrderItem.desc(排序字段)), 查询条件);
于是我们看看查询的结果,嗯?为什么依旧没有排序?查看日志,粗大问题了惹。
failed to concat orderBy from IPage, exception=null
这是什么原因?没办法继续查看底层实现。手动跟进debug看到了原由
final public Statement Statement() throws ParseException {/*@bgen(jjtree) Statement */
SimpleNode jjtn000 = new SimpleNode(JJTSTATEMENT);
boolean jjtc000 = true;
jjtree.openNodeScope(jjtn000);
jjtn000.jjtSetFirstToken(getToken(1));Statement stm = null;
try {
try {
stm = SingleStatement();
switch ((jj_ntk==-1)?jj_ntk_f():jj_ntk) {
case ST_SEMICOLON:{
jj_consume_token(ST_SEMICOLON);
break;
}
default:
jj_la1[0] = jj_gen;
;
}
......
在这里报错了!
原来mybatis会调用CCJSqlParser去解析,那么为什么会解析失败啊?
这里我们直接调用CCJSqlParserUtil去看看我们的sql为什么会这样!!
String sql = "你的sql";
try {
CCJSqlParserUtil.parse(sql);
} catch (JSQLParserException e) {
e.printStackTrace();
}
通过一遍一遍的修改sql最后终于把问题定位了!!
关键字!
net.sf.jsqlparser.JSQLParserException: Encountered unexpected token: "apply" "APPLY"
at line 1, column 15.
Was expecting one of:
"("
"ACTION"
"ANY"
"BYTE"
"CASCADE"
"CAST"
"CHANGE"
"CHAR"
"CHARACTER"
"COLUMN"
"COLUMNS"
"COMMENT"
"COMMIT"
"CREATE"
"CYCLE"
"DESC"
"DESCRIBE"
"DISABLE"
"DIV"
"DO"
"DOUBLE"
"DUPLICATE"
"ENABLE"
"END"
"EXCLUDE"
"EXTRACT"
"FALSE"
"FIRST"
"FN"
"FOLLOWING"
"FORMAT"
"GROUP"
"IF"
"INDEX"
"INSERT"
"INTERVAL"
"ISNULL"
"KEY"
"LAST"
"LATERAL"
"LEFT"
"LIMIT"
"MATERIALIZED"
"NEXTVAL"
"NO"
"NOLOCK"
"NULLS"
"OF"
"OFFSET"
"ON"
"OPEN"
"OPTIMIZE"
"ORDER"
"OVER"
"PARTITION"
"PATH"
"PERCENT"
"PRECISION"
"PRIMARY"
"PRIOR"
"PROCEDURE"
"PUBLIC"
"RANGE"
"READ"
"REPLACE"
"RIGHT"
"ROW"
"ROWS"
"SCHEMA"
"SEPARATOR"
"SEQUENCE"
"SESSION"
"SET"
"SIBLINGS"
"SIZE"
"START"
"TABLE"
"TABLES"
"TEMP"
"TEMPORARY"
"TO"
"TOP"
"TRUE"
"TRUNCATE"
"TYPE"
"UNSIGNED"
"VALIDATE"
"VALUE"
"VALUES"
"VIEW"
"XML"
"ZONE"
"{"
<K_DATETIMELITERAL>
<K_DATE_LITERAL>
<S_IDENTIFIER>
<S_QUOTED_IDENTIFIER>
万万没想到,因为我们的sql里有apply,居然就一直无法解析!!最坑的是,报错里并没有嗦apply有问题,我一直以为是apply周围有什么字段啥的出问题了。于是我们把sql改一下。
String sql = "select * from \"apply\"";
try {
CCJSqlParserUtil.parse(sql);
} catch (JSQLParserException e) {
e.printStackTrace();
}
Process finished with exit code 0
好了,并没有报错。
于是我们把sql里关键字全部加长""双引号吧,现在sqlserver里跑一下,看看能否识别,再修改自定义sql,在分页的时候加上addOrder排序。
完美解决!
好了,大坑踩完了。GitHub里的issue也有人遇到了同样的问题,建议大家多看看多读读,多阅读源码看看底层