abel533 / MyBatis-Spring-Boot

Spring Boot集成MyBatis的基础项目
3.37k stars 1.59k forks source link

5.1.4的pagehelper的com.github.pagehelper.dialect.helper.OracleDialect类下的public String getPageSql(String sql, Page page, CacheKey pageKey)方法是不是有BUG? #169

Closed shiersong closed 4 years ago

shiersong commented 4 years ago

您好! 我们想请教一下: 我们集成的是:

com.github.pagehelper pagehelper-spring-boot-starter 1.2.5

那么maven会自动下载pagehelper-5.1.4.jar,这个jar包中的com.github.pagehelper.dialect.helper.OracleDialect类下的public String getPageSql(String sql, Page page, CacheKey pageKey)方法逻辑如下: @Override public String getPageSql(String sql, Page page, CacheKey pageKey) { StringBuilder sqlBuilder = new StringBuilder(sql.length() + 120); sqlBuilder.append("SELECT FROM ( "); sqlBuilder.append(" SELECT TMP_PAGE., ROWNUM ROW_ID FROM ( "); sqlBuilder.append(sql); sqlBuilder.append(" ) TMP_PAGE WHERE ROWNUM <= ? "); sqlBuilder.append(" ) WHERE ROW_ID > ? "); return sqlBuilder.toString(); } 在66行-75行之间。 这个方法是用来针对Oracle数据库生成具体的分页SQL的。 这个方法是不是有BUG? 因为我们发现在使用Oracle的实际业务程序中如果使用了ORDER BY字句,并且在分页边界处有多条记录的ORDER BY的字段的值是相同的时候,有的记录在每一页的结果集中都找不到,就是说这种情况下记录有一定几率的丢失。

我打个比方: 每页记录数是10,原业务程序的SQL ORDER BY a,按照原业务程序的SQL查询出来的不分页的结果集中第9条、第10条、第11条的的a字段的值都是1,在实际应用的情况是有一定记录会发生这样的情况: 第10条记录在第一页的结果集中没有,在第二页的结果集中也没有。

个人建议是: 在以后的版本中是不是应该将那个方法改成这样? @Override public String getPageSql(String sql, Page page, CacheKey pageKey) { StringBuilder sqlBuilder = new StringBuilder(sql.length() + 120); sqlBuilder.append("SELECT FROM ( "); sqlBuilder.append(" SELECT TMP_PAGE., ROWNUM rownum_ FROM ( "); sqlBuilder.append(sql); sqlBuilder.append(" ) TMPPAGE "); sqlBuilder.append(" ) WHERE rownum > ? AND rownum_ <= ? "); return sqlBuilder.toString(); } 即在第一次子查询的时候只给原业务SQL的结果集的每一行的ROWNUM起一个别名(rownum),而不对ROWNUM限制条件了,在第二次子查询针对这个别名(rownum),也就是行号,限制上分页边界条件。

而对于我们现有项目的情况,是否可以这样解决实际问题? 1、写一个自定义的Dialect类,继承OracleDialect,并重写public String getPageSql(String sql, Page page, CacheKey pageKey) 方法, 2、并在配置文件中配置pagehelper:dialectAlias:oracle=自定义的Dialect类(基于yml文件方式的配置)