Repository: pagehelper-org/Mybatis-PageHelper Branch: master Commit: b4212c4dbd0f Files: 249 Total size: 1.1 MB Directory structure: gitextract_2of7jm93/ ├── .editorconfig ├── .github/ │ ├── FUNDING.yml │ ├── issue_template.md │ └── workflows/ │ ├── pull-request.yml │ └── release.yml ├── .gitignore ├── LICENSE ├── README.md ├── README_en.md ├── jsqlparser4_7兼容性改动.patch ├── pom.xml ├── src/ │ ├── main/ │ │ └── java/ │ │ └── com/ │ │ └── github/ │ │ └── pagehelper/ │ │ ├── AutoDialect.java │ │ ├── BoundSqlInterceptor.java │ │ ├── BoundSqlInterceptorChain.java │ │ ├── Constant.java │ │ ├── CountMsIdGen.java │ │ ├── Dialect.java │ │ ├── IPage.java │ │ ├── ISelect.java │ │ ├── Page.java │ │ ├── PageException.java │ │ ├── PageHelper.java │ │ ├── PageInfo.java │ │ ├── PageInterceptor.java │ │ ├── PageParam.java │ │ ├── PageProperties.java │ │ ├── PageRowBounds.java │ │ ├── PageSerializable.java │ │ ├── QueryInterceptor.java │ │ ├── cache/ │ │ │ ├── Cache.java │ │ │ ├── CacheFactory.java │ │ │ ├── GuavaCache.java │ │ │ └── SimpleCache.java │ │ ├── dialect/ │ │ │ ├── AbstractDialect.java │ │ │ ├── AbstractHelperDialect.java │ │ │ ├── AbstractRowBoundsDialect.java │ │ │ ├── ReplaceSql.java │ │ │ ├── auto/ │ │ │ │ ├── C3P0AutoDialect.java │ │ │ │ ├── DataSourceAutoDialect.java │ │ │ │ ├── DataSourceNegotiationAutoDialect.java │ │ │ │ ├── DbcpAutoDialect.java │ │ │ │ ├── DefaultAutoDialect.java │ │ │ │ ├── DruidAutoDialect.java │ │ │ │ ├── HikariAutoDialect.java │ │ │ │ └── TomcatAutoDialect.java │ │ │ ├── helper/ │ │ │ │ ├── AS400Dialect.java │ │ │ │ ├── CirroDataDialect.java │ │ │ │ ├── Db2Dialect.java │ │ │ │ ├── FirebirdDialect.java │ │ │ │ ├── GaussDBDialect.java │ │ │ │ ├── HerdDBDialect.java │ │ │ │ ├── HsqldbDialect.java │ │ │ │ ├── InformixDialect.java │ │ │ │ ├── MySqlDialect.java │ │ │ │ ├── Oracle9iDialect.java │ │ │ │ ├── OracleDialect.java │ │ │ │ ├── OscarDialect.java │ │ │ │ ├── PostgreSqlDialect.java │ │ │ │ ├── SqlServer2012Dialect.java │ │ │ │ ├── SqlServerDialect.java │ │ │ │ └── XuguDialect.java │ │ │ ├── replace/ │ │ │ │ ├── RegexWithNolockReplaceSql.java │ │ │ │ └── SimpleWithNolockReplaceSql.java │ │ │ └── rowbounds/ │ │ │ ├── Db2RowBoundsDialect.java │ │ │ ├── GaussDBRowBoundsDialect.java │ │ │ ├── HerdDBRowBoundsDialect.java │ │ │ ├── HsqldbRowBoundsDialect.java │ │ │ ├── InformixRowBoundsDialect.java │ │ │ ├── MySqlRowBoundsDialect.java │ │ │ ├── OracleRowBoundsDialect.java │ │ │ ├── PostgreSqlRowBoundsDialect.java │ │ │ ├── SqlServer2012RowBoundsDialect.java │ │ │ ├── SqlServerRowBoundsDialect.java │ │ │ ├── XuguRowBoundsDialect.java │ │ │ └── package-info.java │ │ ├── page/ │ │ │ ├── PageAutoDialect.java │ │ │ ├── PageBoundSqlInterceptors.java │ │ │ ├── PageMethod.java │ │ │ └── PageParams.java │ │ ├── parser/ │ │ │ ├── CountSqlParser.java │ │ │ ├── OrderBySqlParser.java │ │ │ ├── SqlParser.java │ │ │ ├── SqlParserUtil.java │ │ │ ├── SqlServerSqlParser.java │ │ │ └── defaults/ │ │ │ ├── DefaultCountSqlParser.java │ │ │ ├── DefaultOrderBySqlParser.java │ │ │ └── DefaultSqlServerSqlParser.java │ │ └── util/ │ │ ├── ClassUtil.java │ │ ├── ExecutorUtil.java │ │ ├── MSUtils.java │ │ ├── MetaObjectUtil.java │ │ ├── MetaObjectWithReflectCache.java │ │ ├── PageObjectUtil.java │ │ ├── SqlSafeUtil.java │ │ ├── StackTraceUtil.java │ │ └── StringUtil.java │ └── test/ │ ├── java/ │ │ └── com/ │ │ └── github/ │ │ └── pagehelper/ │ │ ├── mapper/ │ │ │ ├── ProviderMethod.java │ │ │ └── UserMapper.java │ │ ├── model/ │ │ │ ├── Code.java │ │ │ ├── User.java │ │ │ ├── UserCode.java │ │ │ ├── UserExample.java │ │ │ └── UserQueryModel.java │ │ ├── rowbounds/ │ │ │ ├── RowBoundsHelper.java │ │ │ └── test/ │ │ │ ├── PageRowBoundsTest.java │ │ │ └── RowBoundsTest.java │ │ ├── sql/ │ │ │ ├── DefaultOrderBySqlParserTest.java │ │ │ ├── SqlServerTest.java │ │ │ └── SqlTest.java │ │ ├── test/ │ │ │ ├── basic/ │ │ │ │ ├── ArgumentsMapTest.java │ │ │ │ ├── ArgumentsObjTest.java │ │ │ │ ├── AsyncCountTest.java │ │ │ │ ├── CloseableTest.java │ │ │ │ ├── CollectionMapTest.java │ │ │ │ ├── CountColumnTest.java │ │ │ │ ├── EnumTest.java │ │ │ │ ├── IPageTest.java │ │ │ │ ├── OffsetTest.java │ │ │ │ ├── PageHelperTest.java │ │ │ │ ├── PageInfoTest.java │ │ │ │ ├── RemoveOrderTest.java │ │ │ │ ├── TestDistinct.java │ │ │ │ ├── TestExecute.java │ │ │ │ ├── TestISelect.java │ │ │ │ ├── TestIntMax.java │ │ │ │ ├── TestLike.java │ │ │ │ ├── TestNamespaceMap.java │ │ │ │ ├── annotations/ │ │ │ │ │ └── TestAnnotations.java │ │ │ │ ├── cache/ │ │ │ │ │ ├── CacheTest.java │ │ │ │ │ └── SecondCacheTest.java │ │ │ │ ├── count/ │ │ │ │ │ ├── TestGroupBy.java │ │ │ │ │ ├── TestOrderBy.java │ │ │ │ │ └── TestSelectItems.java │ │ │ │ ├── dynamic/ │ │ │ │ │ ├── CacheTest.java │ │ │ │ │ ├── TestDynamicChoose.java │ │ │ │ │ ├── TestDynamicForeach.java │ │ │ │ │ ├── TestDynamicIf.java │ │ │ │ │ ├── TestDynamicIf2.java │ │ │ │ │ ├── TestDynamicIfOrder.java │ │ │ │ │ ├── TestDynamicIfTwoList.java │ │ │ │ │ ├── TestDynamicWhere.java │ │ │ │ │ └── Where.java │ │ │ │ ├── example/ │ │ │ │ │ └── TestExample.java │ │ │ │ ├── parameter/ │ │ │ │ │ ├── TestParameterArray.java │ │ │ │ │ ├── TestParameterList.java │ │ │ │ │ ├── TestParameterMap.java │ │ │ │ │ ├── TestParameterNone.java │ │ │ │ │ └── TestParameterOne.java │ │ │ │ ├── provider/ │ │ │ │ │ ├── SqlCache.java │ │ │ │ │ ├── SqlCacheInterceptor.java │ │ │ │ │ ├── TestBoundSqlInterceptor.java │ │ │ │ │ ├── TestProvider.java │ │ │ │ │ └── TestProviderInteceptor.java │ │ │ │ └── sql/ │ │ │ │ ├── TestExists.java │ │ │ │ ├── TestLeftjoin.java │ │ │ │ ├── TestUnion.java │ │ │ │ └── TestWith.java │ │ │ ├── features/ │ │ │ │ ├── autodialect/ │ │ │ │ │ ├── AutoDialectTest.java │ │ │ │ │ ├── DataSourceNegotiationAutoDialectTest.java │ │ │ │ │ └── SimpleAutoDialect.java │ │ │ │ └── dialectclass/ │ │ │ │ └── UsingDialectClassTest.java │ │ │ ├── namespace/ │ │ │ │ └── BasicTest.java │ │ │ ├── pagesize/ │ │ │ │ ├── PageSizeLessThenOrEqualZeroTest.java │ │ │ │ └── PageSizeZeroTest.java │ │ │ ├── reasonable/ │ │ │ │ └── PageTest.java │ │ │ └── rowbounds/ │ │ │ └── RowBoundsTest.java │ │ └── util/ │ │ ├── MybatisAutoDialectHelper.java │ │ ├── MybatisHelper.java │ │ ├── MybatisInterceptorHelper.java │ │ ├── MybatisPageSizeZeroHelper.java │ │ ├── MybatisReasonableHelper.java │ │ ├── MybatisRowBoundsHelper.java │ │ ├── Ognl.java │ │ ├── SqlSafeUtilTest.java │ │ └── TestUtil.java │ └── resources/ │ ├── cirrodata/ │ │ ├── cirrodata.sql │ │ ├── mybatis-config-pagesizezero.xml │ │ ├── mybatis-config-reasonable.xml │ │ ├── mybatis-config-rowbounds.xml │ │ └── mybatis-config.xml │ ├── com/ │ │ └── github/ │ │ └── pagehelper/ │ │ └── mapper/ │ │ └── UserMapper.xml │ ├── db2/ │ │ ├── db2jcc4.jar │ │ ├── mybatis-config-pagesizezero.xml │ │ ├── mybatis-config-reasonable.xml │ │ ├── mybatis-config-rowbounds.xml │ │ └── mybatis-config.xml │ ├── derby/ │ │ ├── derby.sql │ │ ├── mybatis-config-pagesizezero.xml │ │ ├── mybatis-config-reasonable.xml │ │ ├── mybatis-config-rowbounds.xml │ │ └── mybatis-config.xml │ ├── h2/ │ │ ├── h2.sql │ │ ├── mybatis-config-pagesizezero.xml │ │ ├── mybatis-config-reasonable.xml │ │ ├── mybatis-config-rowbounds.xml │ │ └── mybatis-config.xml │ ├── hsqldb/ │ │ ├── hsqldb.sql │ │ ├── mybatis-config-autodialect.xml │ │ ├── mybatis-config-interceptor.xml │ │ ├── mybatis-config-pagesizezero.xml │ │ ├── mybatis-config-reasonable.xml │ │ ├── mybatis-config-rowbounds.xml │ │ └── mybatis-config.xml │ ├── logback.xml │ ├── mariadb/ │ │ ├── mariadb.sql │ │ ├── mybatis-config-pagesizezero.xml │ │ ├── mybatis-config-reasonable.xml │ │ ├── mybatis-config-rowbounds.xml │ │ └── mybatis-config.xml │ ├── mybatis-config-async-count.xml │ ├── mysql/ │ │ ├── mybatis-config-autodialect.xml │ │ ├── mybatis-config-interceptor.xml │ │ ├── mybatis-config-pagesizezero.xml │ │ ├── mybatis-config-reasonable.xml │ │ ├── mybatis-config-rowbounds.xml │ │ ├── mybatis-config.xml │ │ └── mysql.sql │ ├── oracle/ │ │ ├── mybatis-config-pagesizezero.xml │ │ ├── mybatis-config-reasonable.xml │ │ ├── mybatis-config-rowbounds.xml │ │ ├── mybatis-config.xml │ │ └── oracle.sql │ ├── postgresql/ │ │ ├── mybatis-config-pagesizezero.xml │ │ ├── mybatis-config-reasonable.xml │ │ ├── mybatis-config-rowbounds.xml │ │ ├── mybatis-config.xml │ │ └── postgresql.sql │ ├── rowbounds/ │ │ ├── hsqldb.sql │ │ └── mybatis-config.xml │ ├── sqlserver/ │ │ ├── mybatis-config-pagesizezero.xml │ │ ├── mybatis-config-reasonable.xml │ │ ├── mybatis-config-rowbounds.xml │ │ └── mybatis-config.xml │ ├── test.properties │ └── xugu/ │ ├── mybatis-config-interceptor.xml │ ├── mybatis-config-pagesizezero.xml │ ├── mybatis-config-reasonable.xml │ ├── mybatis-config-rowbounds.xml │ ├── mybatis-config.xml │ └── mysql.sql └── wikis/ ├── en/ │ ├── Changelog.md │ ├── HowToUse.md │ ├── Important.md │ └── Test.md └── zh/ ├── Changelog.md ├── HowToUse.md ├── Important.md ├── Interceptor.md └── Test.md ================================================ FILE CONTENTS ================================================ ================================================ FILE: .editorconfig ================================================ root = true [*] charset = utf-8 indent_style = space trim_trailing_whitespace = true insert_final_newline = true end_of_line = lf [*.java] ij_java_align_group_field_declarations = true ================================================ FILE: .github/FUNDING.yml ================================================ # These are supported funding model platforms github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2] patreon: # Replace with a single Patreon username open_collective: # Replace with a single Open Collective username ko_fi: # Replace with a single Ko-fi username tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry liberapay: abel533 issuehunt: # Replace with a single IssueHunt username otechie: # Replace with a single Otechie username custom: ['https://mybatis.io/donates.html'] # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2'] ================================================ FILE: .github/issue_template.md ================================================ --- name: PageHelper issue report template about: If you would like to report a issue to PageHelper, please use this template. --- - [ ] 我已在 [issues](https://github.com/pagehelper/Mybatis-PageHelper/issues) 搜索类似问题,并且不存在相同的问题. ## 异常模板 ### 使用环境 * PageHelper 版本: xxx * 数据库类型和版本: xxx * JDBC_URL: xxx ### SQL 解析错误 #### 分页参数 ```java PageHelper.startPage(1, 10); xxMapper.select(model); ``` #### 原 SQL ```sql select * from xxx where xxx = xxx ``` #### 期望的结果: ```sql select * from xxx where xxx = xxx limit 10 ``` ### 完整异常信息 ``` 异常信息放在这里 ``` ### 其他类型的错误 ## 功能建议 详细说明,尽可能提供(伪)代码示例。 ================================================ FILE: .github/workflows/pull-request.yml ================================================ name: Maven verify on: pull_request: types: [ opened, reopened, edited ] jobs: mvn_verify: runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 - name: Set up Maven Central Repository uses: actions/setup-java@v2 with: java-version: '8' distribution: 'adopt' - name: Run the Maven verify phase run: mvn --batch-mode --update-snapshots -P dev verify -Dsurefire.useFile=false -DdisableXmlReport=true ================================================ FILE: .github/workflows/release.yml ================================================ name: Publish package to the Maven Central Repository on: push: tags: [ "*" ] jobs: publish: runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 - name: Set up Maven Central Repository uses: actions/setup-java@v2 with: java-version: '8' distribution: 'adopt' server-id: ossrh server-username: MAVEN_USERNAME server-password: MAVEN_PASSWORD - id: install-secret-key name: Install gpg secret key run: | cat <(echo -e "${{ secrets.OSSRH_GPG_SECRET_KEY }}") | gpg --batch --import gpg --list-secret-keys --keyid-format LONG - name: Publish package env: MAVEN_USERNAME: ${{ secrets.OSSRH_USERNAME }} MAVEN_PASSWORD: ${{ secrets.OSSRH_TOKEN }} run: | mvn --batch-mode -Dgpg.passphrase=${{ secrets.OSSRH_GPG_SECRET_KEY_PASSWORD }} -P release clean deploy ================================================ FILE: .gitignore ================================================ # Maven # target/ dependency-reduced-pom.xml # IDEA # .idea/ *.iml # Eclipse # .settings/ .classpath .project .vscode/ ================================================ FILE: LICENSE ================================================ The MIT License (MIT) Copyright (c) 2014-2022 abel533@gmail.com Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ================================================ FILE: README.md ================================================ ![MyBatis Pagination - PageHelper](logo.png) # MyBatis 分页插件 - PageHelper [![Build Status](https://travis-ci.org/pagehelper/Mybatis-PageHelper.svg?branch=master)](https://travis-ci.org/pagehelper/Mybatis-PageHelper) [![Maven central](https://maven-badges.herokuapp.com/maven-central/com.github.pagehelper/pagehelper/badge.svg)](https://maven-badges.herokuapp.com/maven-central/com.github.pagehelper/pagehelper) [English](README_en.md) 如果你也在用 MyBatis,建议尝试该分页插件,这一定是最方便使用的分页插件。 分页插件支持任何复杂的单表、多表分页,部分特殊情况请看[重要提示](https://github.com/pagehelper/Mybatis-PageHelper/blob/master/wikis/zh/Important.md)。 想要使用分页插件?请看[如何使用分页插件](https://github.com/pagehelper/Mybatis-PageHelper/blob/master/wikis/zh/HowToUse.md)。 ## 《MyBatis 从入门到精通》 ![MyBatis 从入门到精通](https://github.com/mybatis-book/book/raw/master/book.png) [京东](https://item.jd.com/12103309.html) ,[当当](http://product.dangdang.com/25098208.html) ,[亚马逊](https://www.amazon.cn/MyBatis从入门到精通-刘增辉/dp/B072RC11DM/ref=sr_1_18?ie=UTF8&qid=1498007125&sr=8-18&keywords=mybatis) CSDN博客:http://blog.csdn.net/isea533/article/details/73555400 GitHub项目:https://github.com/mybatis-book/book ## 支持 [MyBatis 3.1.0+](https://github.com/mybatis/mybatis-3) ## PageHelper 6 支持 jdk8+ ## PageHelper 5 支持 jdk6+ ## 物理分页 该插件目前支持以下数据库的物理分页 [PageAutoDialect](src/main/java/com/github/pagehelper/page/PageAutoDialect.java): ```java static { //注册别名 registerDialectAlias("hsqldb",HsqldbDialect.class); registerDialectAlias("h2",HsqldbDialect.class); registerDialectAlias("phoenix",HsqldbDialect.class); registerDialectAlias("postgresql",PostgreSqlDialect.class); registerDialectAlias("mysql",MySqlDialect.class); registerDialectAlias("mariadb",MySqlDialect.class); registerDialectAlias("sqlite",MySqlDialect.class); registerDialectAlias("herddb",HerdDBDialect.class); registerDialectAlias("oracle",OracleDialect.class); registerDialectAlias("oracle9i",Oracle9iDialect.class); registerDialectAlias("db2",Db2Dialect.class); registerDialectAlias("as400",AS400Dialect.class); registerDialectAlias("informix",InformixDialect.class); //解决 informix-sqli #129,仍然保留上面的 registerDialectAlias("informix-sqli",InformixDialect.class); registerDialectAlias("sqlserver",SqlServerDialect.class); registerDialectAlias("sqlserver2012",SqlServer2012Dialect.class); registerDialectAlias("derby",SqlServer2012Dialect.class); //达梦数据库,https://github.com/mybatis-book/book/issues/43 registerDialectAlias("dm",OracleDialect.class); //阿里云PPAS数据库,https://github.com/pagehelper/Mybatis-PageHelper/issues/281 registerDialectAlias("edb",OracleDialect.class); //神通数据库 registerDialectAlias("oscar",OscarDialect.class); registerDialectAlias("clickhouse",MySqlDialect.class); //瀚高数据库 registerDialectAlias("highgo",HsqldbDialect.class); //虚谷数据库 registerDialectAlias("xugu",HsqldbDialect.class); registerDialectAlias("impala",HsqldbDialect.class); registerDialectAlias("firebirdsql",FirebirdDialect.class); //人大金仓数据库 registerDialectAlias("kingbase",PostgreSqlDialect.class); // 人大金仓新版本kingbase8 registerDialectAlias("kingbase8",PostgreSqlDialect.class); //行云数据库 registerDialectAlias("xcloud",CirroDataDialect.class); //openGauss数据库 registerDialectAlias("opengauss",PostgreSqlDialect.class); //注册 AutoDialect //想要实现和以前版本相同的效果时,可以配置 autoDialectClass=old registerAutoDialectAlias("old",DefaultAutoDialect.class); registerAutoDialectAlias("hikari",HikariAutoDialect.class); registerAutoDialectAlias("druid",DruidAutoDialect.class); registerAutoDialectAlias("tomcat-jdbc",TomcatAutoDialect.class); registerAutoDialectAlias("dbcp",DbcpAutoDialect.class); registerAutoDialectAlias("c3p0",C3P0AutoDialect.class); //不配置时,默认使用 DataSourceNegotiationAutoDialect registerAutoDialectAlias("default",DataSourceNegotiationAutoDialect.class); } ``` > 如果你使用的数据库不在这个列表时,你可以配置 `dialectAlias` 参数。 > >这个参数允许配置自定义实现的别名,可以用于根据 JDBCURL 自动获取对应实现,允许通过此种方式覆盖已有的实现,配置示例如(多个配置时使用分号隔开): > >```xml > > > > > >``` ## 使用 [QueryInterceptor 规范](https://github.com/pagehelper/Mybatis-PageHelper/blob/master/src/main/java/com/github/pagehelper/QueryInterceptor.java) [Executor 拦截器高级教程 - QueryInterceptor 规范](https://github.com/pagehelper/Mybatis-PageHelper/blob/master/wikis/zh/Interceptor.md) ## 集成 使用 PageHelper 你只需要在 classpath 中包含 [pagehelper-x.y.z.jar](http://repo1.maven.org/maven2/com/github/pagehelper/pagehelper/) 和 [jsqlparser-x.y.z.jar](http://repo1.maven.org/maven2/com/github/jsqlparser/jsqlparser/)。 > pagehelper 和 jsqlparser 对应关系参考 pom.xml 中的依赖版本。 如果你使用 Maven,你只需要在 pom.xml 中添加下面的依赖: ```xml com.github.pagehelper pagehelper 最新版本 ``` 如果你使用 Spring Boot 可以参考: [pagehelper-spring-boot-starter](https://github.com/pagehelper/pagehelper-spring-boot) [继续查看配置和用法](https://github.com/pagehelper/Mybatis-PageHelper/blob/master/wikis/zh/HowToUse.md) ## 文档: - [如何使用分页插件](https://github.com/pagehelper/Mybatis-PageHelper/blob/master/wikis/zh/HowToUse.md) - [更新日志](https://github.com/pagehelper/Mybatis-PageHelper/blob/master/wikis/zh/Changelog.md) - [重要提示](https://github.com/pagehelper/Mybatis-PageHelper/blob/master/wikis/zh/Important.md) ## Spring 集成示例 - [集成 Spring 3.x](https://github.com/abel533/Mybatis-Spring/tree/spring3.x) - [集成 Spring 4.x](https://github.com/abel533/Mybatis-Spring) - [集成 Spring Boot](https://github.com/abel533/MyBatis-Spring-Boot) ## 提交 BUG https://github.com/pagehelper/Mybatis-PageHelper/issues/new ## 微信公众号 ## 项目的发展离不开你的支持 ### 请作者喝杯咖啡吧! ## 作者信息 网站:https://mybatis.io 作者博客:http://blog.csdn.net/isea533 作者邮箱: abel533@gmail.com 如需加群,请通过 http://mybatis.io 首页按钮加群。 本项目在 github 的项目地址:https://github.com/pagehelper/Mybatis-PageHelper 本项目在 gitosc 的项目地址:http://git.oschina.net/free/Mybatis_PageHelper ## MyBatis-3 - 项目:https://github.com/mybatis/mybatis-3 - 文档:http://mybatis.github.io/mybatis-3/zh/index.html MyBatis 专栏: - [MyBatis示例](http://blog.csdn.net/column/details/mybatis-sample.html) - [MyBatis问题集](http://blog.csdn.net/column/details/mybatisqa.html) ## 感谢所有项目贡献者! ================================================ FILE: README_en.md ================================================ ![MyBatis Pagination - PageHelper](logo.png) # MyBatis Pagination - PageHelper [![Build Status](https://travis-ci.org/pagehelper/Mybatis-PageHelper.svg?branch=master)](https://travis-ci.org/pagehelper/Mybatis-PageHelper) [![Maven central](https://maven-badges.herokuapp.com/maven-central/com.github.pagehelper/pagehelper/badge.svg)](https://maven-badges.herokuapp.com/maven-central/com.github.pagehelper/pagehelper) [中文版文档](README.md) If you are using MyBatis, it is recommended to try this pagination plugin. This must be the **MOST CONVENIENT** pagination plugin. PageHelper supports any complex single-table, multi-table queries. As to some special cases, please refer to the [**Important note**](https://github.com/pagehelper/Mybatis-PageHelper/blob/master/wikis/en/Important.md). Want to use PageHelper? Please check out [**How to use PageHelper**](https://github.com/pagehelper/Mybatis-PageHelper/blob/master/wikis/en/HowToUse.md). ## New JavaDoc https://apidoc.gitee.com/free/Mybatis_PageHelper APIs: https://apidoc.gitee.com/free/Mybatis_PageHelper/com/github/pagehelper/page/PageMethod.html ## 《MyBatis 从入门到精通》 ![MyBatis 从入门到精通](https://github.com/mybatis-book/book/raw/master/book.png) [京东](https://item.jd.com/12103309.html) ,[当当](http://product.dangdang.com/25098208.html) ,[Amazon](https://www.amazon.cn/MyBatis从入门到精通-刘增辉/dp/B072RC11DM/ref=sr_1_18?ie=UTF8&qid=1498007125&sr=8-18&keywords=mybatis) CSDN Blog:http://blog.csdn.net/isea533/article/details/73555400 GitHub:https://github.com/mybatis-book/book ## Support [MyBatis 3.1.0+](https://github.com/mybatis/mybatis-3) ## PageHelper 6 Support jdk8+ ## PageHelper 5 Support jdk6+ ## Physical Paging PageHelper supports the following databases [PageAutoDialect](src/main/java/com/github/pagehelper/page/PageAutoDialect.java): ```java static { //register alias registerDialectAlias("hsqldb",HsqldbDialect.class); registerDialectAlias("h2",HsqldbDialect.class); registerDialectAlias("phoenix",HsqldbDialect.class); registerDialectAlias("postgresql",PostgreSqlDialect.class); registerDialectAlias("mysql",MySqlDialect.class); registerDialectAlias("mariadb",MySqlDialect.class); registerDialectAlias("sqlite",MySqlDialect.class); registerDialectAlias("herddb",HerdDBDialect.class); registerDialectAlias("oracle",OracleDialect.class); registerDialectAlias("oracle9i",Oracle9iDialect.class); registerDialectAlias("db2",Db2Dialect.class); registerDialectAlias("as400",AS400Dialect.class); registerDialectAlias("informix",InformixDialect.class); //Solve informix-sqli #129, still keep the above registerDialectAlias("informix-sqli",InformixDialect.class); registerDialectAlias("sqlserver",SqlServerDialect.class); registerDialectAlias("sqlserver2012",SqlServer2012Dialect.class); registerDialectAlias("derby",SqlServer2012Dialect.class); //达梦数据库,https://github.com/mybatis-book/book/issues/43 registerDialectAlias("dm",OracleDialect.class); //阿里云PPAS数据库,https://github.com/pagehelper/Mybatis-PageHelper/issues/281 registerDialectAlias("edb",OracleDialect.class); //神通数据库 registerDialectAlias("oscar",OscarDialect.class); registerDialectAlias("clickhouse",MySqlDialect.class); //瀚高数据库 registerDialectAlias("highgo",HsqldbDialect.class); //虚谷数据库 registerDialectAlias("xugu",HsqldbDialect.class); registerDialectAlias("impala",HsqldbDialect.class); registerDialectAlias("firebirdsql",FirebirdDialect.class); //人大金仓数据库 registerDialectAlias("kingbase",PostgreSqlDialect.class); // 人大金仓新版本kingbase8 registerDialectAlias("kingbase8",PostgreSqlDialect.class); //行云数据库 registerDialectAlias("xcloud",CirroDataDialect.class); //openGauss数据库 registerDialectAlias("opengauss",PostgreSqlDialect.class); //注册 AutoDialect //If you want to achieve the same effect as the previous version, you can configure it autoDialectClass=old registerAutoDialectAlias("old",DefaultAutoDialect.class); registerAutoDialectAlias("hikari",HikariAutoDialect.class); registerAutoDialectAlias("druid",DruidAutoDialect.class); registerAutoDialectAlias("tomcat-jdbc",TomcatAutoDialect.class); registerAutoDialectAlias("dbcp",DbcpAutoDialect.class); registerAutoDialectAlias("c3p0",C3P0AutoDialect.class); //If not configured, it is used by default DataSourceNegotiationAutoDialect registerAutoDialectAlias("default",DataSourceNegotiationAutoDialect.class); } ``` > If the database you are using is not in this list, you can configure the `dialectAlias` parameter. > > This parameter allows to configure the alias of a custom implementation, > which can be used to automatically obtain the corresponding implementation according to the JDBCURL, > and allows to overwrite the existing implementation in this way. > The configuration example is as follows (use semicolons to separate multiple alias): > >```xml > > > > > >``` ## Use [QueryInterceptor spec](https://github.com/pagehelper/Mybatis-PageHelper/blob/master/src/main/java/com/github/pagehelper/QueryInterceptor.java) ## Installation To use PageHelper, you just need to include the [pagehelper-x.y.z.jar](http://repo1.maven.org/maven2/com/github/pagehelper/pagehelper/) and [jsqlparser-x.y.z.jar](http://repo1.maven.org/maven2/com/github/jsqlparser/jsqlparser/) file in the classpath. > For version matching relation, please refer to the dependent version in pom. If you are using Maven, you could just add the following dependency to your `pom.xml`: ```xml com.github.pagehelper pagehelper latest version ``` If you are using Spring Boot, You can refer to the [pagehelper-spring-boot-starter](https://github.com/pagehelper/pagehelper-spring-boot) [More...](https://github.com/pagehelper/Mybatis-PageHelper/blob/master/wikis/en/HowToUse.md) ## Documentation - [How to use the PageHelper](https://github.com/pagehelper/Mybatis-PageHelper/blob/master/wikis/en/HowToUse.md) - [Changelog](https://github.com/pagehelper/Mybatis-PageHelper/blob/master/wikis/en/Changelog.md) - [Important note](https://github.com/pagehelper/Mybatis-PageHelper/blob/master/wikis/en/Important.md) ## Spring integration sample - [Integration Spring 3.x](https://github.com/abel533/Mybatis-Spring/tree/spring3.x) - [Integration Spring 4.x](https://github.com/abel533/Mybatis-Spring) - [Integration Spring Boot](https://github.com/abel533/MyBatis-Spring-Boot) ## Submit BUG https://github.com/pagehelper/Mybatis-PageHelper/issues/new ## 微信公众号 ## Thank you for your support ### Buy the author a cup of coffee! ## Author Info Web: https://mybatis.io Blog: http://blog.csdn.net/isea533 Email: abel533@gmail.com PageHelper on github:https://github.com/pagehelper/Mybatis-PageHelper PageHelper on gitosc:http://git.oschina.net/free/Mybatis_PageHelper ## MyBatis-3 - Project:https://github.com/mybatis/mybatis-3 - Document:https://mybatis.org/mybatis-3/index.html MyBatis 专栏: - [MyBatis Sample](http://blog.csdn.net/column/details/mybatis-sample.html) - [MyBatis QA](http://blog.csdn.net/column/details/mybatisqa.html) ## Thanks to all the people who already contributed! ================================================ FILE: jsqlparser4_7兼容性改动.patch ================================================ Subject: [PATCH] jsqlparser4.7兼容性改动 --- Index: src/main/java/com/github/pagehelper/parser/OrderByParser.java IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== diff --git a/src/main/java/com/github/pagehelper/parser/OrderByParser.java b/src/main/java/com/github/pagehelper/parser/OrderByParser.java --- a/src/main/java/com/github/pagehelper/parser/OrderByParser.java (revision 1ae113e493b480452c69af931124ebd5c1ce09f6) +++ b/src/main/java/com/github/pagehelper/parser/OrderByParser.java (date 1700463025360) @@ -56,9 +56,8 @@ try { stmt = jSqlParser.parse(sql); Select select = (Select) stmt; - SelectBody selectBody = select.getSelectBody(); //处理body-去最外层order by - List orderByElements = extraOrderBy(selectBody); + List orderByElements = extraOrderBy(select); String defaultOrderBy = PlainSelect.orderByToString(orderByElements); if (defaultOrderBy.indexOf('?') != -1) { throw new PageException("The order by in the original SQL[" + sql + "] contains parameters, so it cannot be modified using the OrderBy plugin!"); @@ -85,25 +84,16 @@ /** * extra order by and set default orderby to null * - * @param selectBody + * @param select */ - public static List extraOrderBy(SelectBody selectBody) { - if (selectBody != null) { - if (selectBody instanceof PlainSelect) { - List orderByElements = ((PlainSelect) selectBody).getOrderByElements(); - ((PlainSelect) selectBody).setOrderByElements(null); + public static List extraOrderBy(Select select) { + if (select != null) { + if (select instanceof PlainSelect || select instanceof SetOperationList) { + List orderByElements = select.getOrderByElements(); + select.setOrderByElements(null); return orderByElements; - } else if (selectBody instanceof WithItem) { - WithItem withItem = (WithItem) selectBody; - if (withItem.getSubSelect() != null) { - return extraOrderBy(withItem.getSubSelect().getSelectBody()); - } - } else { - SetOperationList operationList = (SetOperationList) selectBody; - if (operationList.getSelects() != null && operationList.getSelects().size() > 0) { - List plainSelects = operationList.getSelects(); - return extraOrderBy(plainSelects.get(plainSelects.size() - 1)); - } + } else if (select instanceof ParenthesedSelect) { + extraOrderBy(((ParenthesedSelect) select).getSelect()); } } return null; Index: src/main/java/com/github/pagehelper/parser/SqlServerParser.java IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== diff --git a/src/main/java/com/github/pagehelper/parser/SqlServerParser.java b/src/main/java/com/github/pagehelper/parser/SqlServerParser.java --- a/src/main/java/com/github/pagehelper/parser/SqlServerParser.java (revision 1ae113e493b480452c69af931124ebd5c1ce09f6) +++ b/src/main/java/com/github/pagehelper/parser/SqlServerParser.java (date 1700466304213) @@ -138,64 +138,62 @@ * @return */ protected Select getPageSelect(Select select) { - SelectBody selectBody = select.getSelectBody(); - if (selectBody instanceof SetOperationList) { - selectBody = wrapSetOperationList((SetOperationList) selectBody); + if (select instanceof SetOperationList) { + select = wrapSetOperationList((SetOperationList) select); } //这里的selectBody一定是PlainSelect - if (((PlainSelect) selectBody).getTop() != null) { + if (((PlainSelect) select).getTop() != null) { throw new PageException("The pagination statement already contains the top, and can no longer be used to query the pagination plugin!"); } //获取查询列 - List selectItems = getSelectItems((PlainSelect) selectBody); + List> selectItems = getSelectItems((PlainSelect) select); //对一层的SQL增加ROW_NUMBER() - List autoItems = new ArrayList(); - SelectItem orderByColumn = addRowNumber((PlainSelect) selectBody, autoItems); + List> autoItems = new ArrayList<>(); + SelectItem orderByColumn = addRowNumber((PlainSelect) select, autoItems); //加入自动生成列 - ((PlainSelect) selectBody).addSelectItems(autoItems.toArray(new SelectItem[autoItems.size()])); + ((PlainSelect) select).addSelectItems(autoItems.toArray(new SelectItem[0])); //处理子语句中的order by - processSelectBody(selectBody, 0); + processSelectBody(select, 0); //中层子查询 PlainSelect innerSelectBody = new PlainSelect(); //PAGE_ROW_NUMBER innerSelectBody.addSelectItems(orderByColumn); - innerSelectBody.addSelectItems(selectItems.toArray(new SelectItem[selectItems.size()])); + innerSelectBody.addSelectItems(selectItems.toArray(new SelectItem[0])); //将原始查询作为内层子查询 - SubSelect fromInnerItem = new SubSelect(); - fromInnerItem.setSelectBody(selectBody); + ParenthesedSelect fromInnerItem = new ParenthesedSelect(); + fromInnerItem.setSelect(select); fromInnerItem.setAlias(PAGE_TABLE_ALIAS); innerSelectBody.setFromItem(fromInnerItem); //新建一个select - Select newSelect = new Select(); - PlainSelect newSelectBody = new PlainSelect(); + PlainSelect newSelect = new PlainSelect(); //设置top Top top = new Top(); top.setExpression(new LongValue(Long.MAX_VALUE)); - newSelectBody.setTop(top); + newSelect.setTop(top); //设置order by List orderByElements = new ArrayList(); OrderByElement orderByElement = new OrderByElement(); orderByElement.setExpression(PAGE_ROW_NUMBER_COLUMN); orderByElements.add(orderByElement); - newSelectBody.setOrderByElements(orderByElements); + newSelect.setOrderByElements(orderByElements); //设置where GreaterThan greaterThan = new GreaterThan(); greaterThan.setLeftExpression(PAGE_ROW_NUMBER_COLUMN); greaterThan.setRightExpression(new LongValue(Long.MIN_VALUE)); - newSelectBody.setWhere(greaterThan); + newSelect.setWhere(greaterThan); //设置selectItems - newSelectBody.setSelectItems(selectItems); + newSelect.setSelectItems(selectItems); //设置fromIterm - SubSelect fromItem = new SubSelect(); - fromItem.setSelectBody(innerSelectBody); //中层子查询 + ParenthesedSelect fromItem = new ParenthesedSelect(); + fromItem.setSelect(innerSelectBody); //中层子查询 fromItem.setAlias(PAGE_TABLE_ALIAS); - newSelectBody.setFromItem(fromItem); + newSelect.setFromItem(fromItem); - newSelect.setSelectBody(newSelectBody); if (isNotEmptyList(select.getWithItemsList())) { newSelect.setWithItemsList(select.getWithItemsList()); + select.setWithItemsList(null); } return newSelect; } @@ -206,20 +204,20 @@ * @param setOperationList * @return */ - protected SelectBody wrapSetOperationList(SetOperationList setOperationList) { + protected Select wrapSetOperationList(SetOperationList setOperationList) { //获取最后一个plainSelect - SelectBody setSelectBody = setOperationList.getSelects().get(setOperationList.getSelects().size() - 1); + Select setSelectBody = setOperationList.getSelects().get(setOperationList.getSelects().size() - 1); if (!(setSelectBody instanceof PlainSelect)) { throw new PageException("Unable to process the SQL, you can submit issues in GitHub for help.!"); } PlainSelect plainSelect = (PlainSelect) setSelectBody; PlainSelect selectBody = new PlainSelect(); - List selectItems = getSelectItems(plainSelect); + List> selectItems = getSelectItems(plainSelect); selectBody.setSelectItems(selectItems); //设置fromIterm - SubSelect fromItem = new SubSelect(); - fromItem.setSelectBody(setOperationList); + ParenthesedSelect fromItem = new ParenthesedSelect(); + fromItem.setSelect(setOperationList); fromItem.setAlias(new Alias(WRAP_TABLE)); selectBody.setFromItem(fromItem); //order by @@ -236,33 +234,27 @@ * @param plainSelect * @return */ - protected List getSelectItems(PlainSelect plainSelect) { + protected List> getSelectItems(PlainSelect plainSelect) { //设置selectItems - List selectItems = new ArrayList(); - for (SelectItem selectItem : plainSelect.getSelectItems()) { - //别名需要特殊处理 - if (selectItem instanceof SelectExpressionItem) { - SelectExpressionItem selectExpressionItem = (SelectExpressionItem) selectItem; - if (selectExpressionItem.getAlias() != null) { - //直接使用别名 - Column column = new Column(selectExpressionItem.getAlias().getName()); - SelectExpressionItem expressionItem = new SelectExpressionItem(column); - selectItems.add(expressionItem); - } else if (selectExpressionItem.getExpression() instanceof Column) { - Column column = (Column) selectExpressionItem.getExpression(); - SelectExpressionItem item = null; - if (column.getTable() != null) { - Column newColumn = new Column(column.getColumnName()); - item = new SelectExpressionItem(newColumn); - selectItems.add(item); - } else { - selectItems.add(selectItem); - } + List> selectItems = new ArrayList<>(); + for (SelectItem selectItem : plainSelect.getSelectItems()) { + if (selectItem.getExpression() instanceof AllTableColumns) { + selectItems.add(new SelectItem<>(new AllColumns())); + } else if (selectItem.getAlias() != null) { + //直接使用别名 + Column column = new Column(selectItem.getAlias().getName()); + SelectItem expressionItem = new SelectItem<>(column); + selectItems.add(expressionItem); + } else if (selectItem.getExpression() instanceof Column) { + Column column = (Column) selectItem.getExpression(); + SelectItem item = null; + if (column.getTable() != null) { + Column newColumn = new Column(column.getColumnName()); + item = new SelectItem<>(newColumn); + selectItems.add(item); } else { selectItems.add(selectItem); } - } else if (selectItem instanceof AllTableColumns) { - selectItems.add(new AllColumns()); } else { selectItems.add(selectItem); } @@ -272,8 +264,8 @@ // SELECT * FROM (SELECT *, 1 AS alias FROM TEST) // 不应该为 // SELECT *, alias FROM (SELECT *, 1 AS alias FROM TEST) - for (SelectItem selectItem : selectItems) { - if (selectItem instanceof AllColumns) { + for (SelectItem selectItem : selectItems) { + if (selectItem.getExpression() instanceof AllColumns) { return Collections.singletonList(selectItem); } } @@ -287,7 +279,7 @@ * @param autoItems 自动生成的查询列 * @return ROW_NUMBER() 列 */ - protected SelectItem addRowNumber(PlainSelect plainSelect, List autoItems) { + protected SelectItem addRowNumber(PlainSelect plainSelect, List> autoItems) { //增加ROW_NUMBER() StringBuilder orderByBuilder = new StringBuilder(); orderByBuilder.append("ROW_NUMBER() OVER ("); @@ -301,28 +293,28 @@ } orderByBuilder.append(") "); orderByBuilder.append(PAGE_ROW_NUMBER); - return new SelectExpressionItem(new Column(orderByBuilder.toString())); + return new SelectItem<>(new Column(orderByBuilder.toString())); } /** * 处理selectBody去除Order by * - * @param selectBody + * @param select */ - protected void processSelectBody(SelectBody selectBody, int level) { - if (selectBody != null) { - if (selectBody instanceof PlainSelect) { - processPlainSelect((PlainSelect) selectBody, level + 1); - } else if (selectBody instanceof WithItem) { - WithItem withItem = (WithItem) selectBody; - if (withItem.getSubSelect() != null) { - processSelectBody(withItem.getSubSelect().getSelectBody(), level + 1); + protected void processSelectBody(Select select, int level) { + if (select != null) { + if (select instanceof PlainSelect) { + processPlainSelect((PlainSelect) select, level + 1); + } else if (select instanceof WithItem) { + WithItem withItem = (WithItem) select; + if (withItem.getSelect() != null) { + processSelectBody(withItem.getSelect(), level + 1); } } else { - SetOperationList operationList = (SetOperationList) selectBody; - if (operationList.getSelects() != null && operationList.getSelects().size() > 0) { - List plainSelects = operationList.getSelects(); - for (SelectBody plainSelect : plainSelects) { + SetOperationList operationList = (SetOperationList) select; + if (operationList.getSelects() != null && !operationList.getSelects().isEmpty()) { + List selects = ((SetOperationList) select).getSelects(); + for (Select sel : selects) { + processSelect(sel); + } + if (!orderByHashParameters(select.getOrderByElements())) { + select.setOrderByElements(null); + } + } + /* + if (select instanceof WithItem) { WithItem withItem = (WithItem) selectBody; if (withItem.getSubSelect() != null && !keepSubSelectOrderBy()) { processSelectBody(withItem.getSubSelect().getSelectBody()); } - } else { - SetOperationList operationList = (SetOperationList) selectBody; - if (operationList.getSelects() != null && operationList.getSelects().size() > 0) { - List plainSelects = operationList.getSelects(); - for (SelectBody plainSelect : plainSelects) { - processSelectBody(plainSelect); - } - } - if (!orderByHashParameters(operationList.getOrderByElements())) { - operationList.setOrderByElements(null); - } } + */ } } @@ -272,10 +275,10 @@ * @param withItemsList */ public void processWithItemsList(List withItemsList) { - if (withItemsList != null && withItemsList.size() > 0) { + if (withItemsList != null && !withItemsList.isEmpty()) { for (WithItem item : withItemsList) { - if (item.getSubSelect() != null && !keepSubSelectOrderBy()) { - processSelectBody(item.getSubSelect().getSelectBody()); + if (item.getSelect() != null && !keepSubSelectOrderBy()) { + processSelect(item.getSelect()); } } } @@ -287,33 +290,16 @@ * @param fromItem */ public void processFromItem(FromItem fromItem) { - if (fromItem instanceof SubJoin) { - SubJoin subJoin = (SubJoin) fromItem; - if (subJoin.getJoinList() != null && subJoin.getJoinList().size() > 0) { - for (Join join : subJoin.getJoinList()) { - if (join.getRightItem() != null) { - processFromItem(join.getRightItem()); - } - } - } - if (subJoin.getLeft() != null) { - processFromItem(subJoin.getLeft()); - } - } else if (fromItem instanceof SubSelect) { - SubSelect subSelect = (SubSelect) fromItem; - if (subSelect.getSelectBody() != null && !keepSubSelectOrderBy()) { - processSelectBody(subSelect.getSelectBody()); + if (fromItem instanceof ParenthesedSelect) { + ParenthesedSelect parenthesedSelect = (ParenthesedSelect) fromItem; + if (parenthesedSelect.getSelect() != null && !keepSubSelectOrderBy()) { + processSelect(parenthesedSelect.getSelect()); } - } else if (fromItem instanceof ValuesList) { - - } else if (fromItem instanceof LateralSubSelect) { - LateralSubSelect lateralSubSelect = (LateralSubSelect) fromItem; - if (lateralSubSelect.getSubSelect() != null) { - SubSelect subSelect = lateralSubSelect.getSubSelect(); - if (subSelect.getSelectBody() != null && !keepSubSelectOrderBy()) { - processSelectBody(subSelect.getSelectBody()); - } - } + } else if (fromItem instanceof Select) { + processSelect((Select) fromItem); + } else if (fromItem instanceof ParenthesedFromItem) { + ParenthesedFromItem parenthesedFromItem = (ParenthesedFromItem) fromItem; + processFromItem(parenthesedFromItem.getFromItem()); } //Table时不用处理 } ================================================ FILE: pom.xml ================================================ 4.0.0 com.github.pagehelper pagehelper 6.1.1 jar pagehelper 6 Mybatis Pagination Plugin https://github.com/pagehelper/Mybatis-PageHelper The MIT License (MIT) https://github.com/pagehelper/Mybatis-PageHelper/blob/master/LICENSE abel533 abel533@gmail.com scm:git:git@github.com:pagehelper/Mybatis-PageHelper.git scm:git:git@github.com:pagehelper/Mybatis-PageHelper.git git@github.com:pagehelper/Mybatis-PageHelper.git 8 8 UTF-8 com.github.jsqlparser jsqlparser 4.7 org.mybatis mybatis 3.5.19 compile true com.google.guava guava 33.4.8-jre compile true com.zaxxer HikariCP-java6 2.3.13 compile slf4j-api org.slf4j true com.alibaba druid 1.2.12 compile true org.apache.tomcat tomcat-jdbc 10.0.20 compile true com.mchange c3p0 0.9.5.5 compile true org.apache.commons commons-dbcp2 2.9.0 compile true junit junit 4.13.2 test ch.qos.logback logback-classic 1.2.13 test org.hsqldb hsqldb 2.2.9 test release maven-compiler-plugin org.apache.maven.plugins maven-source-plugin package jar-no-fork org.apache.maven.plugins maven-javadoc-plugin 3.2.0 -Xdoclint:none package jar org.apache.maven.plugins maven-gpg-plugin sign-artifacts verify sign --pinentry-mode loopback org.sonatype.plugins nexus-staging-maven-plugin true ossrh https://oss.sonatype.org/ true ossrh https://oss.sonatype.org/content/repositories/snapshots/ ossrh https://oss.sonatype.org/service/local/staging/deploy/maven2/ org.apache.maven.plugins maven-surefire-plugin -Dfile.encoding=UTF-8 ================================================ FILE: src/main/java/com/github/pagehelper/AutoDialect.java ================================================ /* * The MIT License (MIT) * * Copyright (c) 2014-2023 abel533@gmail.com * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ package com.github.pagehelper; import com.github.pagehelper.dialect.AbstractHelperDialect; import org.apache.ibatis.mapping.MappedStatement; import javax.sql.DataSource; import java.util.Properties; /** * 自动获取方言 * * @param 缓存key类型 */ public interface AutoDialect { /** * 获取用于缓存 {@link #extractDialect } 方法返回值的 key,当返回 null 时不缓存,返回值时先判断是否已存在,不存在时调用 {@link #extractDialect } 再缓存 * * @param ms * @param dataSource * @param properties * @return */ K extractDialectKey(MappedStatement ms, DataSource dataSource, Properties properties); /** * 提取 dialect * * @param dialectKey * @param ms * @param dataSource * @param properties * @return */ AbstractHelperDialect extractDialect(K dialectKey, MappedStatement ms, DataSource dataSource, Properties properties); } ================================================ FILE: src/main/java/com/github/pagehelper/BoundSqlInterceptor.java ================================================ /* * The MIT License (MIT) * * Copyright (c) 2014-2023 abel533@gmail.com * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ package com.github.pagehelper; import org.apache.ibatis.cache.CacheKey; import org.apache.ibatis.mapping.BoundSql; /** * BoundSql 处理器 */ public interface BoundSqlInterceptor { /** * boundsql 处理 * * @param type 类型 * @param boundSql 当前类型的 boundSql * @param cacheKey 缓存 key * @param chain 处理器链,通过 chain.doBoundSql 方法继续执行后续方法,也可以直接返回 boundSql 终止后续方法的执行 * @return 允许修改 boundSql 并返回修改后的 */ BoundSql boundSql(Type type, BoundSql boundSql, CacheKey cacheKey, Chain chain); enum Type { /** * 原始SQL,分页插件执行前,先执行这个类型 */ ORIGINAL, /** * count SQL,第二个执行这里 */ COUNT_SQL, /** * 分页 SQL,最后执行这里 */ PAGE_SQL } /** * 处理器链,可以控制是否继续执行 */ interface Chain { Chain DO_NOTHING = (type, boundSql, cacheKey) -> boundSql; BoundSql doBoundSql(Type type, BoundSql boundSql, CacheKey cacheKey); } } ================================================ FILE: src/main/java/com/github/pagehelper/BoundSqlInterceptorChain.java ================================================ /* * The MIT License (MIT) * * Copyright (c) 2014-2023 abel533@gmail.com * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ package com.github.pagehelper; import org.apache.ibatis.cache.CacheKey; import org.apache.ibatis.mapping.BoundSql; import java.util.List; public class BoundSqlInterceptorChain implements BoundSqlInterceptor.Chain { private final BoundSqlInterceptor.Chain original; private final List interceptors; private int index = 0; private boolean executable; public BoundSqlInterceptorChain(BoundSqlInterceptor.Chain original, List interceptors) { this(original, interceptors, false); } private BoundSqlInterceptorChain(BoundSqlInterceptor.Chain original, List interceptors, boolean executable) { this.original = original; this.interceptors = interceptors; this.executable = executable; } @Override public BoundSql doBoundSql(BoundSqlInterceptor.Type type, BoundSql boundSql, CacheKey cacheKey) { if(executable) { return _doBoundSql(type, boundSql, cacheKey); } else { return new BoundSqlInterceptorChain(original, interceptors, true).doBoundSql(type, boundSql, cacheKey); } } private BoundSql _doBoundSql(BoundSqlInterceptor.Type type, BoundSql boundSql, CacheKey cacheKey) { if (this.interceptors == null || this.interceptors.size() == this.index) { return this.original != null ? this.original.doBoundSql(type, boundSql, cacheKey) : boundSql; } else { return this.interceptors.get(this.index++).boundSql(type, boundSql, cacheKey, this); } } } ================================================ FILE: src/main/java/com/github/pagehelper/Constant.java ================================================ /* * The MIT License (MIT) * * Copyright (c) 2014-2023 abel533@gmail.com * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ package com.github.pagehelper; /** * @author liuzh */ public interface Constant { //分页的id后缀 String SUFFIX_PAGE = "_PageHelper"; //count查询的id后缀 String SUFFIX_COUNT = SUFFIX_PAGE + "_Count"; //第一个分页参数 String PAGEPARAMETER_FIRST = "First" + SUFFIX_PAGE; //第二个分页参数 String PAGEPARAMETER_SECOND = "Second" + SUFFIX_PAGE; } ================================================ FILE: src/main/java/com/github/pagehelper/CountMsIdGen.java ================================================ /* * The MIT License (MIT) * * Copyright (c) 2014-2023 abel533@gmail.com * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ package com.github.pagehelper; import org.apache.ibatis.mapping.BoundSql; import org.apache.ibatis.mapping.MappedStatement; /** * 构建当前查询对应的 count 方法 id *

* 返回的 msId 会先判断是否存在自定义的方法,存在就直接使用 *

* 如果不存在,会根据当前的 msId 创建 MappedStatement * * @author liuzh */ public interface CountMsIdGen { /** * 默认实现 */ CountMsIdGen DEFAULT = (ms, parameter, boundSql, countSuffix) -> ms.getId() + countSuffix; /** * 构建当前查询对应的 count 方法 id * * @param ms 查询对应的 MappedStatement * @param parameter 方法参数 * @param boundSql 查询SQL * @param countSuffix 配置的 count 后缀 * @return count 查询丢的 msId */ String genCountMsId(MappedStatement ms, Object parameter, BoundSql boundSql, String countSuffix); } ================================================ FILE: src/main/java/com/github/pagehelper/Dialect.java ================================================ /* * The MIT License (MIT) * * Copyright (c) 2014-2023 abel533@gmail.com * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ package com.github.pagehelper; import org.apache.ibatis.cache.CacheKey; import org.apache.ibatis.mapping.BoundSql; import org.apache.ibatis.mapping.MappedStatement; import org.apache.ibatis.session.RowBounds; import java.util.List; import java.util.Properties; import java.util.concurrent.Callable; import java.util.concurrent.ForkJoinPool; import java.util.concurrent.Future; /** * 数据库方言,针对不同数据库进行实现 * * @author liuzh */ public interface Dialect { /** * 跳过 count 和 分页查询 * * @param ms MappedStatement * @param parameterObject 方法参数 * @param rowBounds 分页参数 * @return true 跳过,返回默认查询结果,false 执行分页查询 */ boolean skip(MappedStatement ms, Object parameterObject, RowBounds rowBounds); /** * 是否使用异步 count 查询,使用异步后不会根据返回的 count 数来判断是否有必要进行分页查询 * * @return true 异步,false 同步 */ default boolean isAsyncCount() { return false; } /** * 执行异步 count 查询 * * @param task 异步查询任务 * @param * @return */ default Future asyncCountTask(Callable task) { return ForkJoinPool.commonPool().submit(task); } /** * 执行分页前,返回 true 会进行 count 查询,false 会继续下面的 beforePage 判断 * * @param ms MappedStatement * @param parameterObject 方法参数 * @param rowBounds 分页参数 * @return */ boolean beforeCount(MappedStatement ms, Object parameterObject, RowBounds rowBounds); /** * 生成 count 查询 sql * * @param ms MappedStatement * @param boundSql 绑定 SQL 对象 * @param parameterObject 方法参数 * @param rowBounds 分页参数 * @param countKey count 缓存 key * @return */ String getCountSql(MappedStatement ms, BoundSql boundSql, Object parameterObject, RowBounds rowBounds, CacheKey countKey); /** * 执行完 count 查询后 * * @param count 查询结果总数 * @param parameterObject 接口参数 * @param rowBounds 分页参数 * @return true 继续分页查询,false 直接返回 */ boolean afterCount(long count, Object parameterObject, RowBounds rowBounds); /** * 处理查询参数对象 * * @param ms MappedStatement * @param parameterObject * @param boundSql * @param pageKey * @return */ Object processParameterObject(MappedStatement ms, Object parameterObject, BoundSql boundSql, CacheKey pageKey); /** * 执行分页前,返回 true 会进行分页查询,false 会返回默认查询结果 * * @param ms MappedStatement * @param parameterObject 方法参数 * @param rowBounds 分页参数 * @return */ boolean beforePage(MappedStatement ms, Object parameterObject, RowBounds rowBounds); /** * 生成分页查询 sql * * @param ms MappedStatement * @param boundSql 绑定 SQL 对象 * @param parameterObject 方法参数 * @param rowBounds 分页参数 * @param pageKey 分页缓存 key * @return */ String getPageSql(MappedStatement ms, BoundSql boundSql, Object parameterObject, RowBounds rowBounds, CacheKey pageKey); /** * 分页查询后,处理分页结果,拦截器中直接 return 该方法的返回值 * * @param pageList 分页查询结果 * @param parameterObject 方法参数 * @param rowBounds 分页参数 * @return */ Object afterPage(List pageList, Object parameterObject, RowBounds rowBounds); /** * 完成所有任务后 */ void afterAll(); /** * 设置参数 * * @param properties 插件属性 */ void setProperties(Properties properties); } ================================================ FILE: src/main/java/com/github/pagehelper/IPage.java ================================================ /* * The MIT License (MIT) * * Copyright (c) 2014-2023 abel533@gmail.com * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ package com.github.pagehelper; /** * @author liuzh */ public interface IPage { Integer getPageNum(); Integer getPageSize(); String getOrderBy(); } ================================================ FILE: src/main/java/com/github/pagehelper/ISelect.java ================================================ /* * The MIT License (MIT) * * Copyright (c) 2014-2023 abel533@gmail.com * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ package com.github.pagehelper; /** * 分页查询接口 * * @author liuzh_3nofxnp * @since 2015-12-18 18:51 */ public interface ISelect { /** * 在接口中调用自己的查询方法,不要在该方法内写过多代码,只要一行查询方法最好 */ void doSelect(); } ================================================ FILE: src/main/java/com/github/pagehelper/Page.java ================================================ /* * The MIT License (MIT) * * Copyright (c) 2014-2023 abel533@gmail.com * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ package com.github.pagehelper; import com.github.pagehelper.util.SqlSafeUtil; import com.github.pagehelper.util.StackTraceUtil; import org.apache.ibatis.logging.Log; import org.apache.ibatis.logging.LogFactory; import java.io.Closeable; import java.util.ArrayList; import java.util.List; /** * Mybatis - 分页对象 * * @author liuzh/abel533/isea533 * @version 3.6.0 * 项目地址 : http://git.oschina.net/free/Mybatis_PageHelper */ public class Page extends ArrayList implements Closeable { private static final long serialVersionUID = 1L; private static final Log log = LogFactory.getLog(Page.class); /** * 记录当前堆栈,可查找到page在何处创建 * 需开启pagehelper.debug */ private final String stackTrace = PageInterceptor.isDebug() ? StackTraceUtil.current() : null; /** * 页码,从1开始 */ private int pageNum; /** * 页面大小 */ private int pageSize; /** * 起始行 */ private long startRow; /** * 末行 */ private long endRow; /** * 总数 */ private long total; /** * 总页数 */ private int pages; /** * 包含count查询 */ private boolean count = true; /** * 分页合理化 */ private Boolean reasonable; /** * 当设置为true的时候,如果pagesize设置为0(或RowBounds的limit=0),就不执行分页,返回全部结果 */ private Boolean pageSizeZero; /** * 进行count查询的列名 */ private String countColumn; /** * 排序 */ private String orderBy; /** * 只增加排序 */ private boolean orderByOnly; /** * sql拦截处理 */ private BoundSqlInterceptor boundSqlInterceptor; private transient BoundSqlInterceptor.Chain chain; /** * 分页实现类,可以使用 {@link com.github.pagehelper.page.PageAutoDialect} 类中注册的别名,例如 "mysql", "oracle" */ private String dialectClass; /** * 转换count查询时保留查询的 order by 排序 */ private Boolean keepOrderBy; /** * 转换count查询时保留子查询的 order by 排序 */ private Boolean keepSubSelectOrderBy; /** * 异步count查询 */ private Boolean asyncCount; public Page() { super(); } public Page(int pageNum, int pageSize) { this(pageNum, pageSize, true, null); } public Page(int pageNum, int pageSize, boolean count) { this(pageNum, pageSize, count, null); } private Page(int pageNum, int pageSize, boolean count, Boolean reasonable) { super(0); if (pageNum == 1 && pageSize == Integer.MAX_VALUE) { pageSizeZero = true; pageSize = 0; } this.pageNum = pageNum; this.pageSize = pageSize; this.count = count; calculateStartAndEndRow(); setReasonable(reasonable); } /** * int[] rowBounds * 0 : offset * 1 : limit */ public Page(int[] rowBounds, boolean count) { super(0); if (rowBounds[0] == 0 && rowBounds[1] == Integer.MAX_VALUE) { pageSizeZero = true; this.pageSize = 0; this.pageNum = 1; } else { this.pageSize = rowBounds[1]; this.pageNum = rowBounds[1] != 0 ? (int) (Math.ceil(((double) rowBounds[0] + rowBounds[1]) / rowBounds[1])) : 0; } this.startRow = rowBounds[0]; this.count = count; this.endRow = this.startRow + rowBounds[1]; } public String getStackTrace() { return stackTrace; } public List getResult() { return this; } public int getPages() { return pages; } public Page setPages(int pages) { this.pages = pages; return this; } public long getEndRow() { return endRow; } public Page setEndRow(long endRow) { this.endRow = endRow; return this; } public int getPageNum() { return pageNum; } public Page setPageNum(int pageNum) { //分页合理化,针对不合理的页码自动处理 this.pageNum = ((reasonable != null && reasonable) && pageNum <= 0) ? 1 : pageNum; return this; } public int getPageSize() { return pageSize; } public Page setPageSize(int pageSize) { this.pageSize = pageSize; return this; } public long getStartRow() { return startRow; } public Page setStartRow(long startRow) { this.startRow = startRow; return this; } public long getTotal() { return total; } public void setTotal(long total) { this.total = total; if (total == -1) { pages = 1; return; } if (pageSize > 0) { pages = (int) (total / pageSize + ((total % pageSize == 0) ? 0 : 1)); } else { pages = 0; } //分页合理化,针对不合理的页码自动处理 if ((reasonable != null && reasonable) && pageNum > pages) { if (pages != 0) { pageNum = pages; } calculateStartAndEndRow(); } } public Boolean getReasonable() { return reasonable; } public Page setReasonable(Boolean reasonable) { if (reasonable == null) { return this; } this.reasonable = reasonable; //分页合理化,针对不合理的页码自动处理 if (this.reasonable && this.pageNum <= 0) { this.pageNum = 1; calculateStartAndEndRow(); } return this; } public Boolean getPageSizeZero() { return pageSizeZero; } public Page setPageSizeZero(Boolean pageSizeZero) { if (this.pageSizeZero == null && pageSizeZero != null) { this.pageSizeZero = pageSizeZero; } return this; } public String getOrderBy() { return orderBy; } /** * 设置排序字段,增加 SQL 注入校验,如果需要在 order by 使用函数,可以使用 {@link #setUnsafeOrderBy(String)} 方法 * * @param orderBy 排序字段 */ public Page setOrderBy(String orderBy) { if (SqlSafeUtil.check(orderBy)) { throw new PageException("order by [" + orderBy + "] has a risk of SQL injection, " + "if you want to avoid SQL injection verification, you can call Page.setUnsafeOrderBy"); } this.orderBy = orderBy; return (Page) this; } /** * 不安全的设置排序方法,如果从前端接收参数,请自行做好注入校验。 *

* 请不要故意使用该方法注入然后提交漏洞!!! * * @param orderBy 排序字段 */ public Page setUnsafeOrderBy(String orderBy) { this.orderBy = orderBy; return (Page) this; } public boolean isOrderByOnly() { return orderByOnly; } public void setOrderByOnly(boolean orderByOnly) { this.orderByOnly = orderByOnly; } public String getDialectClass() { return dialectClass; } public void setDialectClass(String dialectClass) { this.dialectClass = dialectClass; } public Boolean getKeepOrderBy() { return keepOrderBy; } public Page setKeepOrderBy(Boolean keepOrderBy) { this.keepOrderBy = keepOrderBy; return this; } public Boolean getKeepSubSelectOrderBy() { return keepSubSelectOrderBy; } public void setKeepSubSelectOrderBy(Boolean keepSubSelectOrderBy) { this.keepSubSelectOrderBy = keepSubSelectOrderBy; } public Boolean getAsyncCount() { return asyncCount; } public void setAsyncCount(Boolean asyncCount) { this.asyncCount = asyncCount; } /** * 指定使用的分页实现,如果自己使用的很频繁,建议自己增加一层封装再使用 * * @param dialect 分页实现类,可以使用 {@link com.github.pagehelper.page.PageAutoDialect} 类中注册的别名,例如 "mysql", "oracle" * @return */ public Page using(String dialect) { this.dialectClass = dialect; return this; } /** * 计算起止行号 */ private void calculateStartAndEndRow() { this.startRow = this.pageNum > 0 ? (this.pageNum - 1) * this.pageSize : 0; this.endRow = this.startRow + this.pageSize * (this.pageNum > 0 ? 1 : 0); } public boolean isCount() { return this.count; } public Page setCount(boolean count) { this.count = count; return this; } /** * 设置页码 * * @param pageNum * @return */ public Page pageNum(int pageNum) { //分页合理化,针对不合理的页码自动处理 this.pageNum = ((reasonable != null && reasonable) && pageNum <= 0) ? 1 : pageNum; return this; } /** * 设置页面大小 * * @param pageSize * @return */ public Page pageSize(int pageSize) { this.pageSize = pageSize; calculateStartAndEndRow(); return this; } /** * 是否执行count查询 * * @param count * @return */ public Page count(Boolean count) { this.count = count; return this; } /** * 设置合理化 * * @param reasonable * @return */ public Page reasonable(Boolean reasonable) { setReasonable(reasonable); return this; } /** * 当设置为true的时候,如果pagesize设置为0(或RowBounds的limit=0),就不执行分页,返回全部结果 * * @param pageSizeZero * @return */ public Page pageSizeZero(Boolean pageSizeZero) { setPageSizeZero(pageSizeZero); return this; } /** * 设置 BoundSql 拦截器 * * @param boundSqlInterceptor * @return */ public Page boundSqlInterceptor(BoundSqlInterceptor boundSqlInterceptor) { setBoundSqlInterceptor(boundSqlInterceptor); return this; } /** * 指定 count 查询列 * * @param columnName * @return */ public Page countColumn(String columnName) { setCountColumn(columnName); return this; } /** * 转换count查询时保留查询的 order by 排序 * * @param keepOrderBy * @return */ public Page keepOrderBy(boolean keepOrderBy) { this.keepOrderBy = keepOrderBy; return this; } public boolean keepOrderBy() { return this.keepOrderBy != null && this.keepOrderBy; } /** * 转换count查询时保留子查询的 order by 排序 * * @param keepSubSelectOrderBy * @return */ public Page keepSubSelectOrderBy(boolean keepSubSelectOrderBy) { this.keepSubSelectOrderBy = keepSubSelectOrderBy; return this; } public boolean keepSubSelectOrderBy() { return this.keepSubSelectOrderBy != null && this.keepSubSelectOrderBy; } /** * 异步count查询 * * @param asyncCount * @return */ public Page asyncCount(boolean asyncCount) { this.asyncCount = asyncCount; return this; } /** * 使用异步count查询 * * @return */ public Page enableAsyncCount() { return asyncCount(true); } /** * 不使用异步count查询 * * @return */ public Page disableAsyncCount() { return asyncCount(false); } public boolean asyncCount() { return this.asyncCount != null && this.asyncCount; } public PageInfo toPageInfo() { return new PageInfo(this); } /** * 数据对象转换 * * @param function * @param * @return */ public PageInfo toPageInfo(Function function) { List list = new ArrayList(this.size()); for (E e : this) { list.add(function.apply(e)); } PageInfo pageInfo = new PageInfo(list); pageInfo.setTotal(this.getTotal()); pageInfo.setPageNum(this.getPageNum()); pageInfo.setPageSize(this.getPageSize()); pageInfo.setPages(this.getPages()); pageInfo.setStartRow(this.getStartRow()); pageInfo.setEndRow(this.getEndRow()); pageInfo.calcByNavigatePages(PageInfo.DEFAULT_NAVIGATE_PAGES); return pageInfo; } public PageSerializable toPageSerializable() { return new PageSerializable(this); } /** * 数据对象转换 * * @param function * @param * @return */ public PageSerializable toPageSerializable(Function function) { List list = new ArrayList(this.size()); for (E e : this) { list.add(function.apply(e)); } PageSerializable pageSerializable = new PageSerializable(list); pageSerializable.setTotal(this.getTotal()); return pageSerializable; } public Page doSelectPage(ISelect select) { select.doSelect(); return (Page) this; } public PageInfo doSelectPageInfo(ISelect select) { select.doSelect(); return (PageInfo) this.toPageInfo(); } public PageSerializable doSelectPageSerializable(ISelect select) { select.doSelect(); return (PageSerializable) this.toPageSerializable(); } public long doCount(ISelect select) { this.pageSizeZero = true; this.pageSize = 0; select.doSelect(); return this.total; } public String getCountColumn() { return countColumn; } public void setCountColumn(String countColumn) { if (!"0".equals(countColumn) && !"*".equals(countColumn) && SqlSafeUtil.check(countColumn)) { throw new PageException("count(" + countColumn + ") has a risk of SQL injection"); } this.countColumn = countColumn; } public BoundSqlInterceptor getBoundSqlInterceptor() { return boundSqlInterceptor; } public void setBoundSqlInterceptor(BoundSqlInterceptor boundSqlInterceptor) { this.boundSqlInterceptor = boundSqlInterceptor; } BoundSqlInterceptor.Chain getChain() { return chain; } void setChain(BoundSqlInterceptor.Chain chain) { this.chain = chain; } @Override public String toString() { return "Page{" + "count=" + count + ", pageNum=" + pageNum + ", pageSize=" + pageSize + ", startRow=" + startRow + ", endRow=" + endRow + ", total=" + total + ", pages=" + pages + ", reasonable=" + reasonable + ", pageSizeZero=" + pageSizeZero + '}' + super.toString(); } @Override public void close() { PageHelper.clearPage(); } /** * 兼容低版本 Java 7- */ public interface Function { /** * Applies this function to the given argument. * * @param t the function argument * @return the function result */ T apply(E t); } } ================================================ FILE: src/main/java/com/github/pagehelper/PageException.java ================================================ /* * The MIT License (MIT) * * Copyright (c) 2014-2023 abel533@gmail.com * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ package com.github.pagehelper; /** * 分页插件异常 */ public class PageException extends RuntimeException { public PageException() { super(); } public PageException(String message) { super(message); } public PageException(String message, Throwable cause) { super(message, cause); } public PageException(Throwable cause) { super(cause); } } ================================================ FILE: src/main/java/com/github/pagehelper/PageHelper.java ================================================ /* * The MIT License (MIT) * * Copyright (c) 2014-2023 abel533@gmail.com * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ package com.github.pagehelper; import com.github.pagehelper.dialect.AbstractHelperDialect; import com.github.pagehelper.page.PageAutoDialect; import com.github.pagehelper.page.PageBoundSqlInterceptors; import com.github.pagehelper.page.PageMethod; import com.github.pagehelper.page.PageParams; import com.github.pagehelper.parser.CountSqlParser; import com.github.pagehelper.util.StringUtil; import org.apache.ibatis.cache.CacheKey; import org.apache.ibatis.mapping.BoundSql; import org.apache.ibatis.mapping.MappedStatement; import org.apache.ibatis.session.RowBounds; import java.util.Arrays; import java.util.List; import java.util.Properties; import java.util.UUID; import java.util.concurrent.Callable; import java.util.concurrent.ForkJoinPool; import java.util.concurrent.ForkJoinWorkerThread; import java.util.concurrent.Future; /** * Mybatis - 通用分页拦截器
* 项目地址 : http://git.oschina.net/free/Mybatis_PageHelper * * @author liuzh/abel533/isea533 * @version 5.0.0 */ public class PageHelper extends PageMethod implements Dialect, BoundSqlInterceptor.Chain { private PageParams pageParams; private PageAutoDialect autoDialect; private PageBoundSqlInterceptors pageBoundSqlInterceptors; private ForkJoinPool asyncCountService; @Override public boolean skip(MappedStatement ms, Object parameterObject, RowBounds rowBounds) { Page page = pageParams.getPage(parameterObject, rowBounds); if (page == null) { return true; } else { //设置默认的 count 列 if (StringUtil.isEmpty(page.getCountColumn())) { page.setCountColumn(pageParams.getCountColumn()); } //设置默认的异步 count 设置 if (page.getAsyncCount() == null) { page.setAsyncCount(pageParams.isAsyncCount()); } autoDialect.initDelegateDialect(ms, page.getDialectClass()); return false; } } @Override public boolean isAsyncCount() { return getLocalPage().asyncCount(); } @Override public Future asyncCountTask(Callable task) { //异步执行时需要将ThreadLocal值传递,否则会找不到 AbstractHelperDialect dialectThreadLocal = autoDialect.getDialectThreadLocal(); Page localPage = getLocalPage(); String countId = UUID.randomUUID().toString(); return asyncCountService.submit(() -> { try { //设置 ThreadLocal autoDialect.setDialectThreadLocal(dialectThreadLocal); setLocalPage(localPage); return task.call(); } finally { autoDialect.clearDelegate(); clearPage(); } }); } @Override public boolean beforeCount(MappedStatement ms, Object parameterObject, RowBounds rowBounds) { return autoDialect.getDelegate().beforeCount(ms, parameterObject, rowBounds); } @Override public String getCountSql(MappedStatement ms, BoundSql boundSql, Object parameterObject, RowBounds rowBounds, CacheKey countKey) { return autoDialect.getDelegate().getCountSql(ms, boundSql, parameterObject, rowBounds, countKey); } @Override public boolean afterCount(long count, Object parameterObject, RowBounds rowBounds) { return autoDialect.getDelegate().afterCount(count, parameterObject, rowBounds); } @Override public Object processParameterObject(MappedStatement ms, Object parameterObject, BoundSql boundSql, CacheKey pageKey) { return autoDialect.getDelegate().processParameterObject(ms, parameterObject, boundSql, pageKey); } @Override public boolean beforePage(MappedStatement ms, Object parameterObject, RowBounds rowBounds) { return autoDialect.getDelegate().beforePage(ms, parameterObject, rowBounds); } @Override public String getPageSql(MappedStatement ms, BoundSql boundSql, Object parameterObject, RowBounds rowBounds, CacheKey pageKey) { return autoDialect.getDelegate().getPageSql(ms, boundSql, parameterObject, rowBounds, pageKey); } public String getPageSql(String sql, Page page, RowBounds rowBounds, CacheKey pageKey) { return autoDialect.getDelegate().getPageSql(sql, page, pageKey); } @Override public Object afterPage(List pageList, Object parameterObject, RowBounds rowBounds) { //这个方法即使不分页也会被执行,所以要判断 null AbstractHelperDialect delegate = autoDialect.getDelegate(); if (delegate != null) { return delegate.afterPage(pageList, parameterObject, rowBounds); } return pageList; } @Override public void afterAll() { //这个方法即使不分页也会被执行,所以要判断 null AbstractHelperDialect delegate = autoDialect.getDelegate(); if (delegate != null) { delegate.afterAll(); autoDialect.clearDelegate(); } clearPage(); } @Override public BoundSql doBoundSql(BoundSqlInterceptor.Type type, BoundSql boundSql, CacheKey cacheKey) { Page localPage = getLocalPage(); BoundSqlInterceptor.Chain chain = localPage != null ? localPage.getChain() : null; if (chain == null) { BoundSqlInterceptor boundSqlInterceptor = localPage != null ? localPage.getBoundSqlInterceptor() : null; BoundSqlInterceptor.Chain defaultChain = pageBoundSqlInterceptors != null ? pageBoundSqlInterceptors.getChain() : null; if (boundSqlInterceptor != null) { chain = new BoundSqlInterceptorChain(defaultChain, Arrays.asList(boundSqlInterceptor)); } else if (defaultChain != null) { chain = defaultChain; } if (chain == null) { chain = DO_NOTHING; } if (localPage != null) { localPage.setChain(chain); } } return chain.doBoundSql(type, boundSql, cacheKey); } @Override public void setProperties(Properties properties) { setStaticProperties(properties); pageParams = new PageParams(); autoDialect = new PageAutoDialect(); pageBoundSqlInterceptors = new PageBoundSqlInterceptors(); pageParams.setProperties(properties); autoDialect.setProperties(properties); pageBoundSqlInterceptors.setProperties(properties); //20180902新增 aggregateFunctions, 允许手动添加聚合函数(影响行数) CountSqlParser.addAggregateFunctions(properties.getProperty("aggregateFunctions")); // 异步 asyncCountService 并发度设置,这里默认为应用可用的处理器核心数 * 2,更合理的值应该综合考虑数据库服务器的处理能力 int asyncCountParallelism = Integer.parseInt(properties.getProperty("asyncCountParallelism", "" + (Runtime.getRuntime().availableProcessors() * 2))); asyncCountService = new ForkJoinPool(asyncCountParallelism, pool -> { final ForkJoinWorkerThread worker = ForkJoinPool.defaultForkJoinWorkerThreadFactory.newThread(pool); worker.setName("pagehelper-async-count-" + worker.getPoolIndex()); return worker; }, null, true); } } ================================================ FILE: src/main/java/com/github/pagehelper/PageInfo.java ================================================ /* * The MIT License (MIT) * * Copyright (c) 2014-2023 abel533@gmail.com * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ package com.github.pagehelper; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.List; /** * 对Page结果进行包装 *

* 新增分页的多项属性,主要参考:http://bbs.csdn.net/topics/360010907 * * @author liuzh/abel533/isea533 * @version 3.3.0 * @since 3.2.2 * 项目地址 : http://git.oschina.net/free/Mybatis_PageHelper */ @SuppressWarnings({"rawtypes", "unchecked"}) public class PageInfo extends PageSerializable { public static final int DEFAULT_NAVIGATE_PAGES = 8; //private PageInfo EMPTY = new PageInfo(Collections.emptyList(), 0); /** * 当前页 */ private int pageNum; /** * 每页的数量 */ private int pageSize; /** * 当前页的数量 */ private int size; /** * 由于startRow和endRow不常用,这里说个具体的用法 * 可以在页面中"显示startRow到endRow 共size条数据" * 当前页面第一个元素在数据库中的行号 */ private long startRow; /** * 当前页面最后一个元素在数据库中的行号 */ private long endRow; /** * 总页数 */ private int pages; /** * 前一页 */ private int prePage; /** * 下一页 */ private int nextPage; /** * 是否为第一页 */ private boolean isFirstPage = false; /** * 是否为最后一页 */ private boolean isLastPage = false; /** * 是否有前一页 */ private boolean hasPreviousPage = false; /** * 是否有下一页 */ private boolean hasNextPage = false; /** * 导航页码数 */ private int navigatePages; /** * 所有导航页号 */ private int[] navigatepageNums; /** * 导航条上的第一页 */ private int navigateFirstPage; /** * 导航条上的最后一页 */ private int navigateLastPage; public PageInfo() { } /** * 包装Page对象 * * @param list */ public PageInfo(List list) { this(list, DEFAULT_NAVIGATE_PAGES); } /** * 包装Page对象 * * @param list page结果 * @param navigatePages 页码数量 */ public PageInfo(List list, int navigatePages) { super(list); if (list instanceof Page) { Page page = (Page) list; this.pageNum = page.getPageNum(); this.pageSize = page.getPageSize(); this.pages = page.getPages(); this.size = page.size(); //由于结果是>startRow的,所以实际的需要+1 if (this.size == 0) { this.startRow = 0; this.endRow = 0; } else { this.startRow = page.getStartRow() + 1; //计算实际的endRow(最后一页的时候特殊) this.endRow = this.startRow - 1 + this.size; } } else if (list instanceof Collection) { this.pageNum = 1; this.pageSize = list.size(); this.pages = this.pageSize > 0 ? 1 : 0; this.size = list.size(); this.startRow = 0; this.endRow = list.size() > 0 ? list.size() - 1 : 0; } if (list instanceof Collection) { calcByNavigatePages(navigatePages); } } public static PageInfo of(List list) { return new PageInfo(list); } /** * 手动指定总记录数获取分页信息 * * @param total 总记录数 * @param list page结果 */ public static PageInfo of(long total, List list) { if (list instanceof Page) { Page page = (Page) list; page.setTotal(total); } return new PageInfo(list); } public static PageInfo of(List list, int navigatePages) { return new PageInfo(list, navigatePages); } /** * 返回一个空的 Pageinfo 对象 * * @return */ public static PageInfo emptyPageInfo() { return new PageInfo(Collections.emptyList(), 0); } public void calcByNavigatePages(int navigatePages) { setNavigatePages(navigatePages); //计算导航页 calcNavigatepageNums(); //计算前后页,第一页,最后一页 calcPage(); //判断页面边界 judgePageBoudary(); } /** * 计算导航页 */ private void calcNavigatepageNums() { //当总页数小于或等于导航页码数时 if (pages <= navigatePages) { navigatepageNums = new int[pages]; for (int i = 0; i < pages; i++) { navigatepageNums[i] = i + 1; } } else { //当总页数大于导航页码数时 navigatepageNums = new int[navigatePages]; int startNum = pageNum - navigatePages / 2; int endNum = pageNum + navigatePages / 2; if (startNum < 1) { startNum = 1; //(最前navigatePages页 for (int i = 0; i < navigatePages; i++) { navigatepageNums[i] = startNum++; } } else if (endNum > pages) { endNum = pages; //最后navigatePages页 for (int i = navigatePages - 1; i >= 0; i--) { navigatepageNums[i] = endNum--; } } else { //所有中间页 for (int i = 0; i < navigatePages; i++) { navigatepageNums[i] = startNum++; } } } } /** * 计算前后页,第一页,最后一页 */ private void calcPage() { if (navigatepageNums != null && navigatepageNums.length > 0) { navigateFirstPage = navigatepageNums[0]; navigateLastPage = navigatepageNums[navigatepageNums.length - 1]; if (pageNum > 1) { prePage = pageNum - 1; } if (pageNum < pages) { nextPage = pageNum + 1; } } } /** * 判定页面边界 */ private void judgePageBoudary() { isFirstPage = pageNum == 1; isLastPage = pageNum == pages || pages == 0; hasPreviousPage = pageNum > 1; hasNextPage = pageNum < pages; } /** * 数据对象转换 * * @param function 用以转换数据对象的函数 * @param 目标类型 * @return 转换了对象类型的包装结果 */ public PageInfo convert(Page.Function function) { List list = new ArrayList(this.list.size()); for (T t : this.list) { list.add(function.apply(t)); } PageInfo newPageInfo = new PageInfo<>(list); newPageInfo.setPageNum(this.pageNum); newPageInfo.setPageSize(this.pageSize); newPageInfo.setSize(this.size); newPageInfo.setStartRow(this.startRow); newPageInfo.setEndRow(this.endRow); newPageInfo.setTotal(this.total); newPageInfo.setPages(this.pages); newPageInfo.setPrePage(this.prePage); newPageInfo.setNextPage(this.nextPage); newPageInfo.setIsFirstPage(this.isFirstPage); newPageInfo.setIsLastPage(this.isLastPage); newPageInfo.setHasPreviousPage(this.hasPreviousPage); newPageInfo.setHasNextPage(this.hasNextPage); newPageInfo.setNavigatePages(this.navigatePages); newPageInfo.setNavigateFirstPage(this.navigateFirstPage); newPageInfo.setNavigateLastPage(this.navigateLastPage); newPageInfo.setNavigatepageNums(this.navigatepageNums); return newPageInfo; } /** * 是否包含内容 */ public boolean hasContent() { return this.size > 0; } public int getPageNum() { return pageNum; } public void setPageNum(int pageNum) { this.pageNum = pageNum; } public int getPageSize() { return pageSize; } public void setPageSize(int pageSize) { this.pageSize = pageSize; } public int getSize() { return size; } public void setSize(int size) { this.size = size; } public long getStartRow() { return startRow; } public void setStartRow(long startRow) { this.startRow = startRow; } public long getEndRow() { return endRow; } public void setEndRow(long endRow) { this.endRow = endRow; } public int getPages() { return pages; } public void setPages(int pages) { this.pages = pages; } public int getPrePage() { return prePage; } public void setPrePage(int prePage) { this.prePage = prePage; } public int getNextPage() { return nextPage; } public void setNextPage(int nextPage) { this.nextPage = nextPage; } public boolean isIsFirstPage() { return isFirstPage; } public void setIsFirstPage(boolean isFirstPage) { this.isFirstPage = isFirstPage; } public boolean isIsLastPage() { return isLastPage; } public void setIsLastPage(boolean isLastPage) { this.isLastPage = isLastPage; } public boolean isHasPreviousPage() { return hasPreviousPage; } public void setHasPreviousPage(boolean hasPreviousPage) { this.hasPreviousPage = hasPreviousPage; } public boolean isHasNextPage() { return hasNextPage; } public void setHasNextPage(boolean hasNextPage) { this.hasNextPage = hasNextPage; } public int getNavigatePages() { return navigatePages; } public void setNavigatePages(int navigatePages) { this.navigatePages = navigatePages; } public int[] getNavigatepageNums() { return navigatepageNums; } public void setNavigatepageNums(int[] navigatepageNums) { this.navigatepageNums = navigatepageNums; } public int getNavigateFirstPage() { return navigateFirstPage; } public int getNavigateLastPage() { return navigateLastPage; } public void setNavigateFirstPage(int navigateFirstPage) { this.navigateFirstPage = navigateFirstPage; } public void setNavigateLastPage(int navigateLastPage) { this.navigateLastPage = navigateLastPage; } @Override public String toString() { final StringBuilder sb = new StringBuilder("PageInfo{"); sb.append("pageNum=").append(pageNum); sb.append(", pageSize=").append(pageSize); sb.append(", size=").append(size); sb.append(", startRow=").append(startRow); sb.append(", endRow=").append(endRow); sb.append(", total=").append(total); sb.append(", pages=").append(pages); sb.append(", list=").append(list); sb.append(", prePage=").append(prePage); sb.append(", nextPage=").append(nextPage); sb.append(", isFirstPage=").append(isFirstPage); sb.append(", isLastPage=").append(isLastPage); sb.append(", hasPreviousPage=").append(hasPreviousPage); sb.append(", hasNextPage=").append(hasNextPage); sb.append(", navigatePages=").append(navigatePages); sb.append(", navigateFirstPage=").append(navigateFirstPage); sb.append(", navigateLastPage=").append(navigateLastPage); sb.append(", navigatepageNums="); if (navigatepageNums == null) { sb.append("null"); } else { sb.append('['); for (int i = 0; i < navigatepageNums.length; ++i) { sb.append(i == 0 ? "" : ", ").append(navigatepageNums[i]); } sb.append(']'); } sb.append('}'); return sb.toString(); } } ================================================ FILE: src/main/java/com/github/pagehelper/PageInterceptor.java ================================================ /* * The MIT License (MIT) * * Copyright (c) 2014-2023 abel533@gmail.com * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ package com.github.pagehelper; import com.github.pagehelper.cache.Cache; import com.github.pagehelper.cache.CacheFactory; import com.github.pagehelper.page.PageMethod; import com.github.pagehelper.util.ClassUtil; import com.github.pagehelper.util.ExecutorUtil; import com.github.pagehelper.util.MSUtils; import com.github.pagehelper.util.StringUtil; import org.apache.ibatis.cache.CacheKey; import org.apache.ibatis.executor.CachingExecutor; import org.apache.ibatis.executor.Executor; import org.apache.ibatis.executor.SimpleExecutor; import org.apache.ibatis.logging.Log; import org.apache.ibatis.logging.LogFactory; import org.apache.ibatis.mapping.BoundSql; import org.apache.ibatis.mapping.Environment; import org.apache.ibatis.mapping.MappedStatement; import org.apache.ibatis.plugin.*; import org.apache.ibatis.session.Configuration; import org.apache.ibatis.session.ResultHandler; import org.apache.ibatis.session.RowBounds; import org.apache.ibatis.transaction.Transaction; import org.apache.ibatis.transaction.TransactionFactory; import org.apache.ibatis.transaction.managed.ManagedTransactionFactory; import java.sql.SQLException; import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.Properties; import java.util.concurrent.Future; /** * Mybatis - 通用分页拦截器 *

* GitHub: https://github.com/pagehelper/Mybatis-PageHelper *

* Gitee : https://gitee.com/free/Mybatis_PageHelper * * @author liuzh/abel533/isea533 * @version 5.0.0 */ @SuppressWarnings({"rawtypes", "unchecked"}) @Intercepts( { @Signature(type = Executor.class, method = "query", args = {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class}), @Signature(type = Executor.class, method = "query", args = {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class, CacheKey.class, BoundSql.class}), } ) public class PageInterceptor implements Interceptor { private static final Log log = LogFactory.getLog(PageInterceptor.class); private static boolean debug = false; protected Cache msCountMap = null; protected CountMsIdGen countMsIdGen = CountMsIdGen.DEFAULT; private volatile Dialect dialect; private String countSuffix = "_COUNT"; private String default_dialect_class = "com.github.pagehelper.PageHelper"; public PageInterceptor() { String bannerEnabled = System.getProperty("pagehelper.banner"); if (StringUtil.isEmpty(bannerEnabled)) { bannerEnabled = System.getenv("PAGEHELPER_BANNER"); } //默认 TRUE if (StringUtil.isEmpty(bannerEnabled) || Boolean.parseBoolean(bannerEnabled)) { log.debug("\n\n" + ",------. ,--. ,--. ,--. \n" + "| .--. ' ,--,--. ,---. ,---. | '--' | ,---. | | ,---. ,---. ,--.--. \n" + "| '--' | ' ,-. | | .-. | | .-. : | .--. | | .-. : | | | .-. | | .-. : | .--' \n" + "| | --' \\ '-' | ' '-' ' \\ --. | | | | \\ --. | | | '-' ' \\ --. | | \n" + "`--' `--`--' .`- / `----' `--' `--' `----' `--' | |-' `----' `--' \n" + " `---' `--' is intercepting.\n"); } } public static boolean isDebug() { return debug; } /** * 输出启用分页方法时的调用堆栈信息 */ protected void debugStackTraceLog() { if (isDebug()) { Page page = PageMethod.getLocalPage(); log.debug(page.getStackTrace()); } } @Override public Object intercept(Invocation invocation) throws Throwable { try { Object[] args = invocation.getArgs(); MappedStatement ms = (MappedStatement) args[0]; Object parameter = args[1]; RowBounds rowBounds = (RowBounds) args[2]; ResultHandler resultHandler = (ResultHandler) args[3]; Executor executor = (Executor) invocation.getTarget(); CacheKey cacheKey; BoundSql boundSql; //由于逻辑关系,只会进入一次 if (args.length == 4) { //4 个参数时 boundSql = ms.getBoundSql(parameter); cacheKey = executor.createCacheKey(ms, parameter, rowBounds, boundSql); } else { //6 个参数时 cacheKey = (CacheKey) args[4]; boundSql = (BoundSql) args[5]; } checkDialectExists(); //对 boundSql 的拦截处理 if (dialect instanceof BoundSqlInterceptor.Chain) { boundSql = ((BoundSqlInterceptor.Chain) dialect).doBoundSql(BoundSqlInterceptor.Type.ORIGINAL, boundSql, cacheKey); } List resultList; //调用方法判断是否需要进行分页,如果不需要,直接返回结果 if (!dialect.skip(ms, parameter, rowBounds)) { //开启debug时,输出触发当前分页执行时的PageHelper调用堆栈 // 如果和当前调用堆栈不一致,说明在启用分页后没有消费,当前线程再次执行时消费,调用堆栈显示的方法使用不安全 debugStackTraceLog(); Future countFuture = null; //判断是否需要进行 count 查询 if (dialect.beforeCount(ms, parameter, rowBounds)) { if (dialect.isAsyncCount()) { countFuture = asyncCount(ms, boundSql, parameter, rowBounds); } else { //查询总数 Long count = count(executor, ms, parameter, rowBounds, null, boundSql); //处理查询总数,返回 true 时继续分页查询,false 时直接返回 if (!dialect.afterCount(count, parameter, rowBounds)) { //当查询总数为 0 时,直接返回空的结果 return dialect.afterPage(new ArrayList(), parameter, rowBounds); } } } resultList = ExecutorUtil.pageQuery(dialect, executor, ms, parameter, rowBounds, resultHandler, boundSql, cacheKey); if (countFuture != null) { Long count = countFuture.get(); dialect.afterCount(count, parameter, rowBounds); } } else { //rowBounds用参数值,不使用分页插件处理时,仍然支持默认的内存分页 resultList = executor.query(ms, parameter, rowBounds, resultHandler, cacheKey, boundSql); } return dialect.afterPage(resultList, parameter, rowBounds); } finally { if (dialect != null) { dialect.afterAll(); } } } /** * 异步查询总数 */ private Future asyncCount(MappedStatement ms, BoundSql boundSql, Object parameter, RowBounds rowBounds) { Configuration configuration = ms.getConfiguration(); //异步不能复用 BoundSql,因为分页使用时会添加分页参数,这里需要复制一个新的 BoundSql countBoundSql = new BoundSql(configuration, boundSql.getSql(), new ArrayList<>(boundSql.getParameterMappings()), parameter); Map additionalParameter = ExecutorUtil.getAdditionalParameter(boundSql); if (additionalParameter != null){ for (String key : additionalParameter.keySet()) { countBoundSql.setAdditionalParameter(key, additionalParameter.get(key)); } } //异步想要起作用需要新的数据库连接,需要独立的事务,创建新的Executor,因此异步查询只适合在独立查询中使用,如果混合增删改操作,不能开启异步 Environment environment = configuration.getEnvironment(); TransactionFactory transactionFactory = null; if (environment == null || environment.getTransactionFactory() == null) { transactionFactory = new ManagedTransactionFactory(); } else { transactionFactory = environment.getTransactionFactory(); } //创建新的事务 Transaction tx = transactionFactory.newTransaction(environment.getDataSource(), null, false); //使用新的 Executor 执行 count 查询,这里没有加载拦截器,避免递归死循环 Executor countExecutor = new CachingExecutor(new SimpleExecutor(configuration, tx)); return dialect.asyncCountTask(() -> { try { return count(countExecutor, ms, parameter, rowBounds, null, countBoundSql); } finally { tx.close(); } }); } /** * Spring bean 方式配置时,如果没有配置属性就不会执行下面的 setProperties 方法,就不会初始化 *

* 因此这里会出现 null 的情况 fixed #26 */ private void checkDialectExists() { if (dialect == null) { synchronized (default_dialect_class) { if (dialect == null) { setProperties(new Properties()); } } } } private Long count(Executor executor, MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) throws SQLException { String countMsId = countMsIdGen.genCountMsId(ms, parameter, boundSql, countSuffix); Long count; //先判断是否存在手写的 count 查询 MappedStatement countMs = ExecutorUtil.getExistedMappedStatement(ms.getConfiguration(), countMsId); if (countMs != null) { count = ExecutorUtil.executeManualCount(executor, countMs, parameter, boundSql, resultHandler); } else { if (msCountMap != null) { countMs = msCountMap.get(countMsId); } //自动创建 if (countMs == null) { //根据当前的 ms 创建一个返回值为 Long 类型的 ms countMs = MSUtils.newCountMappedStatement(ms, countMsId); if (msCountMap != null) { msCountMap.put(countMsId, countMs); } } count = ExecutorUtil.executeAutoCount(this.dialect, executor, countMs, parameter, boundSql, rowBounds, resultHandler); } return count; } @Override public Object plugin(Object target) { return Plugin.wrap(target, this); } @Override public void setProperties(Properties properties) { //缓存 count ms msCountMap = CacheFactory.createCache(properties.getProperty("msCountCache"), "ms", properties); String dialectClass = properties.getProperty("dialect"); if (StringUtil.isEmpty(dialectClass)) { dialectClass = default_dialect_class; } Dialect tempDialect = ClassUtil.newInstance(dialectClass, properties); tempDialect.setProperties(properties); String countSuffix = properties.getProperty("countSuffix"); if (StringUtil.isNotEmpty(countSuffix)) { this.countSuffix = countSuffix; } // debug模式,用于排查不安全分页调用 debug = Boolean.parseBoolean(properties.getProperty("debug")); // 通过 countMsId 配置自定义类 String countMsIdGenClass = properties.getProperty("countMsIdGen"); if (StringUtil.isNotEmpty(countMsIdGenClass)) { countMsIdGen = ClassUtil.newInstance(countMsIdGenClass, properties); } // 初始化完成后再设置值,保证 dialect 完成初始化 dialect = tempDialect; } } ================================================ FILE: src/main/java/com/github/pagehelper/PageParam.java ================================================ /* * The MIT License (MIT) * * Copyright (c) 2014-2023 abel533@gmail.com * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ package com.github.pagehelper; /** * 抽象类,自己的查询类可以继承该类,可以更直接的控制分页参数 */ public class PageParam implements IPage { private Integer pageNum; private Integer pageSize; private String orderBy; public PageParam() { } public PageParam(Integer pageNum, Integer pageSize) { this.pageNum = pageNum; this.pageSize = pageSize; } public PageParam(Integer pageNum, Integer pageSize, String orderBy) { this.pageNum = pageNum; this.pageSize = pageSize; this.orderBy = orderBy; } public void setPageNum(Integer pageNum) { this.pageNum = pageNum; } public void setPageSize(Integer pageSize) { this.pageSize = pageSize; } public void setOrderBy(String orderBy) { this.orderBy = orderBy; } @Override public Integer getPageNum() { return pageNum; } @Override public Integer getPageSize() { return pageSize; } @Override public String getOrderBy() { return orderBy; } } ================================================ FILE: src/main/java/com/github/pagehelper/PageProperties.java ================================================ /* * The MIT License (MIT) * * Copyright (c) 2014-2023 abel533@gmail.com * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ package com.github.pagehelper; import java.util.Properties; /** * 分页配置,实现该接口的类在初始化后会调用 {@link #setProperties(Properties)} 方法 * * @author liuzh */ public interface PageProperties { /** * 设置参数 * * @param properties 插件属性 */ void setProperties(Properties properties); } ================================================ FILE: src/main/java/com/github/pagehelper/PageRowBounds.java ================================================ /* * The MIT License (MIT) * * Copyright (c) 2014-2023 abel533@gmail.com * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ package com.github.pagehelper; import org.apache.ibatis.session.RowBounds; /** * @author liuzenghui */ public class PageRowBounds extends RowBounds { private Long total; private Boolean count; public PageRowBounds(int offset, int limit) { super(offset, limit); } public Long getTotal() { return total; } public void setTotal(Long total) { this.total = total; } public Boolean getCount() { return count; } public void setCount(Boolean count) { this.count = count; } } ================================================ FILE: src/main/java/com/github/pagehelper/PageSerializable.java ================================================ /* * The MIT License (MIT) * * Copyright (c) 2014-2023 abel533@gmail.com * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ package com.github.pagehelper; import java.io.Serializable; import java.util.List; /** * @author liuzh */ public class PageSerializable implements Serializable { private static final long serialVersionUID = 1L; //总记录数 protected long total; //结果集 protected List list; public PageSerializable() { } @SuppressWarnings("unchecked") public PageSerializable(List list) { this.list = (List) list; if(list instanceof Page){ this.total = ((Page)list).getTotal(); } else { this.total = list.size(); } } public static PageSerializable of(List list){ return new PageSerializable(list); } public long getTotal() { return total; } public void setTotal(long total) { this.total = total; } public List getList() { return list; } public void setList(List list) { this.list = list; } @Override public String toString() { return "PageSerializable{" + "total=" + total + ", list=" + list + '}'; } } ================================================ FILE: src/main/java/com/github/pagehelper/QueryInterceptor.java ================================================ /* * The MIT License (MIT) * * Copyright (c) 2014-2023 abel533@gmail.com * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ package com.github.pagehelper; import org.apache.ibatis.cache.CacheKey; import org.apache.ibatis.executor.Executor; import org.apache.ibatis.mapping.BoundSql; import org.apache.ibatis.mapping.MappedStatement; import org.apache.ibatis.plugin.*; import org.apache.ibatis.session.ResultHandler; import org.apache.ibatis.session.RowBounds; import java.util.Properties; /** * QueryInterceptor 规范 * * 详细说明见文档:https://github.com/pagehelper/Mybatis-PageHelper/blob/master/wikis/zh/Interceptor.md * * @author liuzh/abel533/isea533 * @version 1.0.0 */ @Intercepts( { @Signature(type = Executor.class, method = "query", args = {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class}), @Signature(type = Executor.class, method = "query", args = {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class, CacheKey.class, BoundSql.class}), } ) public class QueryInterceptor implements Interceptor { @Override public Object intercept(Invocation invocation) throws Throwable { Object[] args = invocation.getArgs(); MappedStatement ms = (MappedStatement) args[0]; Object parameter = args[1]; RowBounds rowBounds = (RowBounds) args[2]; ResultHandler resultHandler = (ResultHandler) args[3]; Executor executor = (Executor) invocation.getTarget(); CacheKey cacheKey; BoundSql boundSql; //由于逻辑关系,只会进入一次 if(args.length == 4){ //4 个参数时 boundSql = ms.getBoundSql(parameter); cacheKey = executor.createCacheKey(ms, parameter, rowBounds, boundSql); } else { //6 个参数时 cacheKey = (CacheKey) args[4]; boundSql = (BoundSql) args[5]; } //TODO 自己要进行的各种处理 //注:下面的方法可以根据自己的逻辑调用多次,在分页插件中,count 和 page 各调用了一次 return executor.query(ms, parameter, rowBounds, resultHandler, cacheKey, boundSql); } @Override public Object plugin(Object target) { return Plugin.wrap(target, this); } @Override public void setProperties(Properties properties) { } } ================================================ FILE: src/main/java/com/github/pagehelper/cache/Cache.java ================================================ /* * The MIT License (MIT) * * Copyright (c) 2014-2023 abel533@gmail.com * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ package com.github.pagehelper.cache; /** * Simple cache interface * * @author liuzh */ public interface Cache { V get(K key); void put(K key, V value); } ================================================ FILE: src/main/java/com/github/pagehelper/cache/CacheFactory.java ================================================ /* * The MIT License (MIT) * * Copyright (c) 2014-2023 abel533@gmail.com * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ package com.github.pagehelper.cache; import com.github.pagehelper.PageException; import com.github.pagehelper.PageProperties; import com.github.pagehelper.util.StringUtil; import java.lang.reflect.Constructor; import java.util.Properties; /** * CacheFactory * * @author liuzh */ public abstract class CacheFactory { /** * 创建 SQL 缓存 * * @param sqlCacheClass * @return */ public static Cache createCache(String sqlCacheClass, String prefix, Properties properties) { if (StringUtil.isEmpty(sqlCacheClass)) { try { Class.forName("com.google.common.cache.Cache"); return new GuavaCache(properties, prefix); } catch (Throwable t) { return new SimpleCache(properties, prefix); } } else { try { Class clazz = (Class) Class.forName(sqlCacheClass); try { Constructor constructor = clazz.getConstructor(Properties.class, String.class); return constructor.newInstance(properties, prefix); } catch (Exception e) { Cache cache = clazz.newInstance(); if (cache instanceof PageProperties) { ((PageProperties) cache).setProperties(properties); } return cache; } } catch (Throwable t) { throw new PageException("Created Sql Cache [" + sqlCacheClass + "] Error", t); } } } } ================================================ FILE: src/main/java/com/github/pagehelper/cache/GuavaCache.java ================================================ /* * The MIT License (MIT) * * Copyright (c) 2014-2023 abel533@gmail.com * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ package com.github.pagehelper.cache; import com.github.pagehelper.util.StringUtil; import com.google.common.cache.CacheBuilder; import java.util.Properties; import java.util.concurrent.TimeUnit; /** * Simple Guava Cache * * @author liuzh */ public class GuavaCache implements Cache { private final com.google.common.cache.Cache CACHE; public GuavaCache(Properties properties, String prefix) { CacheBuilder cacheBuilder = CacheBuilder.newBuilder(); String maximumSize = properties.getProperty(prefix + ".maximumSize"); if (StringUtil.isNotEmpty(maximumSize)) { cacheBuilder.maximumSize(Long.parseLong(maximumSize)); } else { cacheBuilder.maximumSize(1000); } String expireAfterAccess = properties.getProperty(prefix + ".expireAfterAccess"); if (StringUtil.isNotEmpty(expireAfterAccess)) { cacheBuilder.expireAfterAccess(Long.parseLong(expireAfterAccess), TimeUnit.MILLISECONDS); } String expireAfterWrite = properties.getProperty(prefix + ".expireAfterWrite"); if (StringUtil.isNotEmpty(expireAfterWrite)) { cacheBuilder.expireAfterWrite(Long.parseLong(expireAfterWrite), TimeUnit.MILLISECONDS); } String initialCapacity = properties.getProperty(prefix + ".initialCapacity"); if (StringUtil.isNotEmpty(initialCapacity)) { cacheBuilder.initialCapacity(Integer.parseInt(initialCapacity)); } CACHE = cacheBuilder.build(); } @Override public V get(K key) { return CACHE.getIfPresent(key); } @Override public void put(K key, V value) { CACHE.put(key, value); } } ================================================ FILE: src/main/java/com/github/pagehelper/cache/SimpleCache.java ================================================ /* * The MIT License (MIT) * * Copyright (c) 2014-2023 abel533@gmail.com * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ package com.github.pagehelper.cache; import com.github.pagehelper.util.StringUtil; import org.apache.ibatis.cache.decorators.FifoCache; import org.apache.ibatis.cache.impl.PerpetualCache; import org.apache.ibatis.mapping.CacheBuilder; import java.util.Properties; /** * Simple MyBatis Cache * * @author liuzh */ public class SimpleCache implements Cache { private final org.apache.ibatis.cache.Cache CACHE; public SimpleCache(Properties properties, String prefix) { CacheBuilder cacheBuilder = new CacheBuilder("SQL_CACHE"); String typeClass = properties.getProperty(prefix + ".typeClass"); if (StringUtil.isNotEmpty(typeClass)) { try { cacheBuilder.implementation((Class) Class.forName(typeClass)); } catch (ClassNotFoundException e) { cacheBuilder.implementation(PerpetualCache.class); } } else { cacheBuilder.implementation(PerpetualCache.class); } String evictionClass = properties.getProperty(prefix + ".evictionClass"); if (StringUtil.isNotEmpty(evictionClass)) { try { cacheBuilder.addDecorator((Class) Class.forName(evictionClass)); } catch (ClassNotFoundException e) { cacheBuilder.addDecorator(FifoCache.class); } } else { cacheBuilder.addDecorator(FifoCache.class); } String flushInterval = properties.getProperty(prefix + ".flushInterval"); if (StringUtil.isNotEmpty(flushInterval)) { cacheBuilder.clearInterval(Long.parseLong(flushInterval)); } String size = properties.getProperty(prefix + ".size"); if (StringUtil.isNotEmpty(size)) { cacheBuilder.size(Integer.parseInt(size)); } cacheBuilder.properties(properties); CACHE = cacheBuilder.build(); } @Override public V get(K key) { Object value = CACHE.getObject(key); if (value != null) { return (V) value; } return null; } @Override public void put(K key, V value) { CACHE.putObject(key, value); } } ================================================ FILE: src/main/java/com/github/pagehelper/dialect/AbstractDialect.java ================================================ /* * The MIT License (MIT) * * Copyright (c) 2014-2023 abel533@gmail.com * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ package com.github.pagehelper.dialect; import com.github.pagehelper.Dialect; import com.github.pagehelper.parser.CountSqlParser; import com.github.pagehelper.parser.OrderBySqlParser; import com.github.pagehelper.parser.defaults.DefaultCountSqlParser; import com.github.pagehelper.parser.defaults.DefaultOrderBySqlParser; import com.github.pagehelper.util.ClassUtil; import org.apache.ibatis.cache.CacheKey; import org.apache.ibatis.mapping.BoundSql; import org.apache.ibatis.mapping.MappedStatement; import org.apache.ibatis.session.RowBounds; import java.util.Properties; /** * 基于 CountSqlParser 的智能 Count 查询 * * @author liuzh */ public abstract class AbstractDialect implements Dialect { //处理SQL protected CountSqlParser countSqlParser; protected OrderBySqlParser orderBySqlParser; @Override public String getCountSql(MappedStatement ms, BoundSql boundSql, Object parameterObject, RowBounds rowBounds, CacheKey countKey) { return countSqlParser.getSmartCountSql(boundSql.getSql()); } @Override public void setProperties(Properties properties) { this.countSqlParser = ClassUtil.newInstance(properties.getProperty("countSqlParser"), CountSqlParser.class, properties, DefaultCountSqlParser::new); this.orderBySqlParser = ClassUtil.newInstance(properties.getProperty("orderBySqlParser"), OrderBySqlParser.class, properties, DefaultOrderBySqlParser::new); } } ================================================ FILE: src/main/java/com/github/pagehelper/dialect/AbstractHelperDialect.java ================================================ /* * The MIT License (MIT) * * Copyright (c) 2014-2023 abel533@gmail.com * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ package com.github.pagehelper.dialect; import com.github.pagehelper.Constant; import com.github.pagehelper.Page; import com.github.pagehelper.PageHelper; import com.github.pagehelper.PageRowBounds; import com.github.pagehelper.util.ExecutorUtil; import com.github.pagehelper.util.MetaObjectUtil; import com.github.pagehelper.util.StringUtil; import org.apache.ibatis.builder.annotation.ProviderSqlSource; import org.apache.ibatis.cache.CacheKey; import org.apache.ibatis.mapping.BoundSql; import org.apache.ibatis.mapping.MappedStatement; import org.apache.ibatis.mapping.ParameterMapping; import org.apache.ibatis.reflection.MetaObject; import org.apache.ibatis.session.RowBounds; import java.util.*; /** * 针对 PageHelper 的实现 * * @author liuzh * @since 2016-12-04 14:32 */ public abstract class AbstractHelperDialect extends AbstractDialect implements Constant { /** * 获取分页参数 * * @param * @return */ public Page getLocalPage() { return PageHelper.getLocalPage(); } @Override public final boolean skip(MappedStatement ms, Object parameterObject, RowBounds rowBounds) { //该方法不会被调用 return true; } @Override public boolean beforeCount(MappedStatement ms, Object parameterObject, RowBounds rowBounds) { Page page = getLocalPage(); return !page.isOrderByOnly() && page.isCount(); } @Override public String getCountSql(MappedStatement ms, BoundSql boundSql, Object parameterObject, RowBounds rowBounds, CacheKey countKey) { Page page = getLocalPage(); String countColumn = page.getCountColumn(); if (StringUtil.isNotEmpty(countColumn)) { return countSqlParser.getSmartCountSql(boundSql.getSql(), countColumn); } return countSqlParser.getSmartCountSql(boundSql.getSql()); } @Override public boolean afterCount(long count, Object parameterObject, RowBounds rowBounds) { Page page = getLocalPage(); page.setTotal(count); if (rowBounds instanceof PageRowBounds) { ((PageRowBounds) rowBounds).setTotal(count); } //pageSize < 0 的时候,不执行分页查询 //pageSize = 0 的时候,还需要执行后续查询,但是不会分页 if (page.getPageSizeZero() != null) { //PageSizeZero=false&&pageSize<=0 if (!page.getPageSizeZero() && page.getPageSize() <= 0) { return false; } //PageSizeZero=true&&pageSize<0 返回 false,只有>=0才需要执行后续的 else if (page.getPageSizeZero() && page.getPageSize() < 0) { return false; } } //页码>0 && 开始行数<总行数即可,不需要考虑 pageSize(上面的 if 已经处理不符合要求的值了) return page.getPageNum() > 0 && count > page.getStartRow(); } @Override public Object processParameterObject(MappedStatement ms, Object parameterObject, BoundSql boundSql, CacheKey pageKey) { //处理参数 Page page = getLocalPage(); //如果只是 order by 就不必处理参数 if (page.isOrderByOnly()) { return parameterObject; } Map paramMap = null; if (parameterObject == null) { paramMap = new HashMap(); } else if (parameterObject instanceof Map) { //解决不可变Map的情况 paramMap = new HashMap(); paramMap.putAll((Map) parameterObject); } else { paramMap = new HashMap(); // sqlSource为ProviderSqlSource时,处理只有1个参数的情况 if (ms.getSqlSource() instanceof ProviderSqlSource) { String[] providerMethodArgumentNames = ExecutorUtil.getProviderMethodArgumentNames((ProviderSqlSource) ms.getSqlSource()); if (providerMethodArgumentNames != null && providerMethodArgumentNames.length == 1) { paramMap.put(providerMethodArgumentNames[0], parameterObject); paramMap.put("param1", parameterObject); } } //动态sql时的判断条件不会出现在ParameterMapping中,但是必须有,所以这里需要收集所有的getter属性 //TypeHandlerRegistry可以直接处理的会作为一个直接使用的对象进行处理 boolean hasTypeHandler = ms.getConfiguration().getTypeHandlerRegistry().hasTypeHandler(parameterObject.getClass()); MetaObject metaObject = MetaObjectUtil.forObject(parameterObject); //需要针对注解形式的MyProviderSqlSource保存原值 if (!hasTypeHandler) { for (String name : metaObject.getGetterNames()) { paramMap.put(name, metaObject.getValue(name)); } } //下面这段方法,主要解决一个常见类型的参数时的问题 if (boundSql.getParameterMappings() != null && boundSql.getParameterMappings().size() > 0) { for (ParameterMapping parameterMapping : boundSql.getParameterMappings()) { String name = parameterMapping.getProperty(); if (!name.equals(PAGEPARAMETER_FIRST) && !name.equals(PAGEPARAMETER_SECOND) && paramMap.get(name) == null) { if (hasTypeHandler || parameterMapping.getJavaType().equals(parameterObject.getClass())) { paramMap.put(name, parameterObject); break; } } } } } return processPageParameter(ms, paramMap, page, boundSql, pageKey); } /** * 处理分页参数 * * @param ms * @param paramMap * @param page * @param boundSql * @param pageKey * @return */ public abstract Object processPageParameter(MappedStatement ms, Map paramMap, Page page, BoundSql boundSql, CacheKey pageKey); @Override public boolean beforePage(MappedStatement ms, Object parameterObject, RowBounds rowBounds) { Page page = getLocalPage(); if (page.isOrderByOnly() || page.getPageSize() > 0) { return true; } return false; } @Override public String getPageSql(MappedStatement ms, BoundSql boundSql, Object parameterObject, RowBounds rowBounds, CacheKey pageKey) { String sql = boundSql.getSql(); Page page = getLocalPage(); //支持 order by String orderBy = page.getOrderBy(); if (StringUtil.isNotEmpty(orderBy)) { pageKey.update(orderBy); sql = orderBySqlParser.converToOrderBySql(sql, orderBy); } if (page.isOrderByOnly()) { return sql; } return getPageSql(sql, page, pageKey); } /** * 单独处理分页部分 * * @param sql * @param page * @param pageKey * @return */ public abstract String getPageSql(String sql, Page page, CacheKey pageKey); @Override public Object afterPage(List pageList, Object parameterObject, RowBounds rowBounds) { Page page = getLocalPage(); if (page == null) { return pageList; } page.addAll(pageList); //调整判断顺序,如果查全部,total就是size,如果只排序,也是全部,其他情况下如果不查询count就是-1 if ((page.getPageSizeZero() != null && page.getPageSizeZero()) && page.getPageSize() == 0) { page.setTotal(pageList.size()); } else if (page.isOrderByOnly()) { page.setTotal(pageList.size()); } else if (!page.isCount()) { page.setTotal(-1); } return page; } @Override public void afterAll() { } @Override public void setProperties(Properties properties) { super.setProperties(properties); } /** * @param boundSql * @param ms * @deprecated use {@code handleParameter(BoundSql boundSql, MappedStatement ms, Class firstClass, Class secondClass)} */ @Deprecated protected void handleParameter(BoundSql boundSql, MappedStatement ms) { if (boundSql.getParameterMappings() != null) { handleParameter(boundSql, ms, long.class, long.class); } } protected void handleParameter(BoundSql boundSql, MappedStatement ms, Class firstClass, Class secondClass) { if (boundSql.getParameterMappings() != null) { List newParameterMappings = new ArrayList(boundSql.getParameterMappings()); newParameterMappings.add(new ParameterMapping.Builder(ms.getConfiguration(), PAGEPARAMETER_FIRST, firstClass).build()); newParameterMappings.add(new ParameterMapping.Builder(ms.getConfiguration(), PAGEPARAMETER_SECOND, secondClass).build()); MetaObject metaObject = MetaObjectUtil.forObject(boundSql); metaObject.setValue("parameterMappings", newParameterMappings); } } } ================================================ FILE: src/main/java/com/github/pagehelper/dialect/AbstractRowBoundsDialect.java ================================================ /* * The MIT License (MIT) * * Copyright (c) 2014-2023 abel533@gmail.com * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ package com.github.pagehelper.dialect; import com.github.pagehelper.PageRowBounds; import org.apache.ibatis.cache.CacheKey; import org.apache.ibatis.mapping.BoundSql; import org.apache.ibatis.mapping.MappedStatement; import org.apache.ibatis.session.RowBounds; import java.util.List; import java.util.Properties; /** * 基于 RowBounds 的分页 * * @author liuzh */ public abstract class AbstractRowBoundsDialect extends AbstractDialect { @Override public boolean skip(MappedStatement ms, Object parameterObject, RowBounds rowBounds) { return rowBounds == RowBounds.DEFAULT; } @Override public boolean beforeCount(MappedStatement ms, Object parameterObject, RowBounds rowBounds) { if(rowBounds instanceof PageRowBounds){ PageRowBounds pageRowBounds = (PageRowBounds)rowBounds; return pageRowBounds.getCount() == null || pageRowBounds.getCount(); } return false; } @Override public boolean afterCount(long count, Object parameterObject, RowBounds rowBounds) { //由于 beforeCount 校验,这里一定是 PageRowBounds ((PageRowBounds) rowBounds).setTotal(count); return count > 0; } @Override public Object processParameterObject(MappedStatement ms, Object parameterObject, BoundSql boundSql, CacheKey pageKey) { return parameterObject; } @Override public boolean beforePage(MappedStatement ms, Object parameterObject, RowBounds rowBounds) { return true; } @Override public String getPageSql(MappedStatement ms, BoundSql boundSql, Object parameterObject, RowBounds rowBounds, CacheKey pageKey) { String sql = boundSql.getSql(); return getPageSql(sql, rowBounds, pageKey); } public abstract String getPageSql(String sql, RowBounds rowBounds, CacheKey pageKey); @Override public Object afterPage(List pageList, Object parameterObject, RowBounds rowBounds) { return pageList; } @Override public void afterAll() { } @Override public void setProperties(Properties properties) { super.setProperties(properties); } } ================================================ FILE: src/main/java/com/github/pagehelper/dialect/ReplaceSql.java ================================================ /* * The MIT License (MIT) * * Copyright (c) 2014-2023 abel533@gmail.com * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ package com.github.pagehelper.dialect; /** * 替换和还原 SQL * * @author liuzh * @since 2017/8/23. */ public interface ReplaceSql { /** * 临时替换后用于 jsqlparser 解析 * * @param sql * @return */ String replace(String sql); /** * 还原经过解析后的 sql * * @param sql * @return */ String restore(String sql); } ================================================ FILE: src/main/java/com/github/pagehelper/dialect/auto/C3P0AutoDialect.java ================================================ /* * The MIT License (MIT) * * Copyright (c) 2014-2023 abel533@gmail.com * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ package com.github.pagehelper.dialect.auto; import com.mchange.v2.c3p0.ComboPooledDataSource; /** * c3p0 * * @author liuzh */ public class C3P0AutoDialect extends DataSourceAutoDialect { @Override public String getJdbcUrl(ComboPooledDataSource comboPooledDataSource) { return comboPooledDataSource.getJdbcUrl(); } } ================================================ FILE: src/main/java/com/github/pagehelper/dialect/auto/DataSourceAutoDialect.java ================================================ /* * The MIT License (MIT) * * Copyright (c) 2014-2023 abel533@gmail.com * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ package com.github.pagehelper.dialect.auto; import com.github.pagehelper.AutoDialect; import com.github.pagehelper.dialect.AbstractHelperDialect; import com.github.pagehelper.page.PageAutoDialect; import org.apache.ibatis.mapping.MappedStatement; import javax.sql.DataSource; import java.lang.reflect.ParameterizedType; import java.lang.reflect.Type; import java.util.Properties; /** * 使用 Hikari 连接池时,简单获取 jdbcUrl * * @author liuzh */ public abstract class DataSourceAutoDialect implements AutoDialect { protected Class dataSourceClass; public DataSourceAutoDialect() { Type genericSuperclass = getClass().getGenericSuperclass(); dataSourceClass = (Class) ((ParameterizedType) genericSuperclass).getActualTypeArguments()[0]; } public abstract String getJdbcUrl(Ds ds); @Override public String extractDialectKey(MappedStatement ms, DataSource dataSource, Properties properties) { if (dataSourceClass.isInstance(dataSource)) { return getJdbcUrl((Ds) dataSource); } return null; } @Override public AbstractHelperDialect extractDialect(String dialectKey, MappedStatement ms, DataSource dataSource, Properties properties) { String dialect = PageAutoDialect.fromJdbcUrl(dialectKey); return PageAutoDialect.instanceDialect(dialect, properties); } } ================================================ FILE: src/main/java/com/github/pagehelper/dialect/auto/DataSourceNegotiationAutoDialect.java ================================================ /* * The MIT License (MIT) * * Copyright (c) 2014-2023 abel533@gmail.com * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ package com.github.pagehelper.dialect.auto; import com.github.pagehelper.AutoDialect; import com.github.pagehelper.dialect.AbstractHelperDialect; import org.apache.ibatis.mapping.MappedStatement; import javax.sql.DataSource; import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.Properties; import java.util.concurrent.ConcurrentHashMap; /** * 遍历所有实现,找到匹配的实现 * * @author liuzh */ public class DataSourceNegotiationAutoDialect implements AutoDialect { private static final List AUTO_DIALECTS = new ArrayList(); private Map urlMap = new ConcurrentHashMap(); static { //创建时,初始化所有实现,当依赖的连接池不存在时,这里不会添加成功,所以理论上这里包含的内容不会多,执行时不会迭代多次 try { AUTO_DIALECTS.add(new HikariAutoDialect()); } catch (Exception ignore) { } try { AUTO_DIALECTS.add(new DruidAutoDialect()); } catch (Exception ignore) { } try { AUTO_DIALECTS.add(new TomcatAutoDialect()); } catch (Exception ignore) { } try { AUTO_DIALECTS.add(new C3P0AutoDialect()); } catch (Exception ignore) { } try { AUTO_DIALECTS.add(new DbcpAutoDialect()); } catch (Exception ignore) { } } /** * 允许手工添加额外的实现,实际上没有必要 * * @param autoDialect */ public static void registerAutoDialect(DataSourceAutoDialect autoDialect) { AUTO_DIALECTS.add(autoDialect); } @Override public String extractDialectKey(MappedStatement ms, DataSource dataSource, Properties properties) { for (DataSourceAutoDialect autoDialect : AUTO_DIALECTS) { String dialectKey = autoDialect.extractDialectKey(ms, dataSource, properties); if (dialectKey != null) { if (!urlMap.containsKey(dialectKey)) { urlMap.put(dialectKey, autoDialect); } return dialectKey; } } //都不匹配的时候使用默认方式 return DefaultAutoDialect.DEFAULT.extractDialectKey(ms, dataSource, properties); } @Override public AbstractHelperDialect extractDialect(String dialectKey, MappedStatement ms, DataSource dataSource, Properties properties) { if (dialectKey != null && urlMap.containsKey(dialectKey)) { return urlMap.get(dialectKey).extractDialect(dialectKey, ms, dataSource, properties); } //都不匹配的时候使用默认方式 return DefaultAutoDialect.DEFAULT.extractDialect(dialectKey, ms, dataSource, properties); } } ================================================ FILE: src/main/java/com/github/pagehelper/dialect/auto/DbcpAutoDialect.java ================================================ /* * The MIT License (MIT) * * Copyright (c) 2014-2023 abel533@gmail.com * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ package com.github.pagehelper.dialect.auto; import org.apache.commons.dbcp2.BasicDataSource; /** * commons-dbcp * * @author liuzh */ public class DbcpAutoDialect extends DataSourceAutoDialect { @Override public String getJdbcUrl(BasicDataSource basicDataSource) { return basicDataSource.getUrl(); } } ================================================ FILE: src/main/java/com/github/pagehelper/dialect/auto/DefaultAutoDialect.java ================================================ /* * The MIT License (MIT) * * Copyright (c) 2014-2023 abel533@gmail.com * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ package com.github.pagehelper.dialect.auto; import com.github.pagehelper.AutoDialect; import com.github.pagehelper.PageException; import com.github.pagehelper.dialect.AbstractHelperDialect; import com.github.pagehelper.page.PageAutoDialect; import com.github.pagehelper.util.StringUtil; import org.apache.ibatis.mapping.MappedStatement; import javax.sql.DataSource; import java.sql.Connection; import java.sql.SQLException; import java.util.Properties; /** * 最初的默认实现,获取连接再获取 url,这种方式通用性强,但是性能低,处理不好关闭连接时容易出问题 * * @author liuzh */ public class DefaultAutoDialect implements AutoDialect { public static final AutoDialect DEFAULT = new DefaultAutoDialect(); @Override public String extractDialectKey(MappedStatement ms, DataSource dataSource, Properties properties) { Connection conn = null; try { conn = dataSource.getConnection(); return conn.getMetaData().getURL(); } catch (SQLException e) { throw new PageException(e); } finally { if (conn != null) { try { String closeConn = properties.getProperty("closeConn"); if (StringUtil.isEmpty(closeConn) || Boolean.parseBoolean(closeConn)) { conn.close(); } } catch (SQLException e) { //ignore } } } } @Override public AbstractHelperDialect extractDialect(String dialectKey, MappedStatement ms, DataSource dataSource, Properties properties) { String dialectStr = PageAutoDialect.fromJdbcUrl(dialectKey); if (dialectStr == null) { throw new PageException("The database type cannot be obtained automatically, please specify it via the helperDialect parameter!"); } return PageAutoDialect.instanceDialect(dialectStr, properties); } } ================================================ FILE: src/main/java/com/github/pagehelper/dialect/auto/DruidAutoDialect.java ================================================ /* * The MIT License (MIT) * * Copyright (c) 2014-2023 abel533@gmail.com * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ package com.github.pagehelper.dialect.auto; import com.alibaba.druid.pool.DruidDataSource; /** * Druid * * @author liuzh */ public class DruidAutoDialect extends DataSourceAutoDialect { @Override public String getJdbcUrl(DruidDataSource druidDataSource) { return druidDataSource.getUrl(); } } ================================================ FILE: src/main/java/com/github/pagehelper/dialect/auto/HikariAutoDialect.java ================================================ /* * The MIT License (MIT) * * Copyright (c) 2014-2023 abel533@gmail.com * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ package com.github.pagehelper.dialect.auto; import com.zaxxer.hikari.HikariDataSource; /** * Hikari * * @author liuzh */ public class HikariAutoDialect extends DataSourceAutoDialect { @Override public String getJdbcUrl(HikariDataSource hikariDataSource) { return hikariDataSource.getJdbcUrl(); } } ================================================ FILE: src/main/java/com/github/pagehelper/dialect/auto/TomcatAutoDialect.java ================================================ /* * The MIT License (MIT) * * Copyright (c) 2014-2023 abel533@gmail.com * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ package com.github.pagehelper.dialect.auto; import org.apache.tomcat.jdbc.pool.DataSource; /** * tomcat-jdbc * * @author liuzh */ public class TomcatAutoDialect extends DataSourceAutoDialect { @Override public String getJdbcUrl(DataSource dataSource) { return dataSource.getUrl(); } } ================================================ FILE: src/main/java/com/github/pagehelper/dialect/helper/AS400Dialect.java ================================================ /* * The MIT License (MIT) * * Copyright (c) 2014-2023 abel533@gmail.com * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ package com.github.pagehelper.dialect.helper; import com.github.pagehelper.Page; import com.github.pagehelper.dialect.AbstractHelperDialect; import org.apache.ibatis.cache.CacheKey; import org.apache.ibatis.mapping.BoundSql; import org.apache.ibatis.mapping.MappedStatement; import java.util.Map; /** * @author bluezealot */ @SuppressWarnings("rawtypes") public class AS400Dialect extends AbstractHelperDialect { @Override public Object processPageParameter(MappedStatement ms, Map paramMap, Page page, BoundSql boundSql, CacheKey pageKey) { paramMap.put(PAGEPARAMETER_FIRST, page.getStartRow()); paramMap.put(PAGEPARAMETER_SECOND, page.getPageSize()); pageKey.update(page.getStartRow()); pageKey.update(page.getPageSize()); handleParameter(boundSql, ms, long.class, int.class); return paramMap; } @Override public String getPageSql(String sql, Page page, CacheKey pageKey) { return sql + " OFFSET ? ROWS FETCH FIRST ? ROWS ONLY"; } } ================================================ FILE: src/main/java/com/github/pagehelper/dialect/helper/CirroDataDialect.java ================================================ /* * The MIT License (MIT) * * Copyright (c) 2014-2023 abel533@gmail.com * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ package com.github.pagehelper.dialect.helper; import com.github.pagehelper.Page; import com.github.pagehelper.dialect.AbstractHelperDialect; import org.apache.ibatis.cache.CacheKey; import org.apache.ibatis.mapping.BoundSql; import org.apache.ibatis.mapping.MappedStatement; import java.util.Map; /** * @author sxh */ public class CirroDataDialect extends AbstractHelperDialect { @Override public Object processPageParameter(MappedStatement ms, Map paramMap, Page page, BoundSql boundSql, CacheKey pageKey) { paramMap.put(PAGEPARAMETER_FIRST, page.getStartRow() + 1); paramMap.put(PAGEPARAMETER_SECOND, page.getEndRow()); //处理pageKey pageKey.update(page.getStartRow() + 1); pageKey.update(page.getEndRow()); //处理参数配置 handleParameter(boundSql, ms, long.class, long.class); return paramMap; } @Override public String getPageSql(String sql, Page page, CacheKey pageKey) { StringBuilder sqlBuilder = new StringBuilder(sql.length() + 16); sqlBuilder.append(sql); sqlBuilder.append("\n LIMIT ( ?, ? )"); return sqlBuilder.toString(); } } ================================================ FILE: src/main/java/com/github/pagehelper/dialect/helper/Db2Dialect.java ================================================ /* * The MIT License (MIT) * * Copyright (c) 2014-2023 abel533@gmail.com * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ package com.github.pagehelper.dialect.helper; import com.github.pagehelper.Page; import com.github.pagehelper.dialect.AbstractHelperDialect; import org.apache.ibatis.cache.CacheKey; import org.apache.ibatis.mapping.BoundSql; import org.apache.ibatis.mapping.MappedStatement; import java.util.Map; /** * @author liuzh */ public class Db2Dialect extends AbstractHelperDialect { @Override public Object processPageParameter(MappedStatement ms, Map paramMap, Page page, BoundSql boundSql, CacheKey pageKey) { paramMap.put(PAGEPARAMETER_FIRST, page.getStartRow() + 1); paramMap.put(PAGEPARAMETER_SECOND, page.getEndRow()); //处理pageKey pageKey.update(page.getStartRow() + 1); pageKey.update(page.getEndRow()); //处理参数配置 handleParameter(boundSql, ms, long.class, long.class); return paramMap; } @Override public String getPageSql(String sql, Page page, CacheKey pageKey) { StringBuilder sqlBuilder = new StringBuilder(sql.length() + 140); sqlBuilder.append("SELECT * FROM (SELECT TMP_PAGE.*,ROWNUMBER() OVER() AS PAGEHELPER_ROW_ID FROM ( \n"); sqlBuilder.append(sql); sqlBuilder.append("\n ) AS TMP_PAGE) TMP_PAGE WHERE PAGEHELPER_ROW_ID BETWEEN ? AND ?"); return sqlBuilder.toString(); } } ================================================ FILE: src/main/java/com/github/pagehelper/dialect/helper/FirebirdDialect.java ================================================ /* * The MIT License (MIT) * * Copyright (c) 2014-2023 abel533@gmail.com * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ package com.github.pagehelper.dialect.helper; import com.github.pagehelper.Page; import com.github.pagehelper.dialect.AbstractHelperDialect; import org.apache.ibatis.cache.CacheKey; import org.apache.ibatis.mapping.BoundSql; import org.apache.ibatis.mapping.MappedStatement; import java.util.Map; /** * firebirdsql数据库 *
    *
  • https://firebirdsql.github.io/jaybird-manual/jaybird_manual.html
  • *
  • https://firebirdsql.org/file/documentation/chunk/en/refdocs/fblangref40/fblangref40-dml.html#fblangref40-dml-select-offsetfetch
  • *
* * @author liuzh */ public class FirebirdDialect extends AbstractHelperDialect { @Override public Object processPageParameter(MappedStatement ms, Map paramMap, Page page, BoundSql boundSql, CacheKey pageKey) { paramMap.put(PAGEPARAMETER_FIRST, page.getStartRow()); paramMap.put(PAGEPARAMETER_SECOND, page.getPageSize()); //处理pageKey pageKey.update(page.getStartRow()); pageKey.update(page.getPageSize()); //处理参数配置 handleParameter(boundSql, ms, long.class, int.class); return paramMap; } @Override public String getPageSql(String sql, Page page, CacheKey pageKey) { StringBuilder sqlBuilder = new StringBuilder(sql.length() + 64); sqlBuilder.append(sql); sqlBuilder.append("\n OFFSET ? ROWS FETCH NEXT ? ROWS ONLY "); pageKey.update(page.getPageSize()); return sqlBuilder.toString(); } } ================================================ FILE: src/main/java/com/github/pagehelper/dialect/helper/GaussDBDialect.java ================================================ /* * The MIT License (MIT) * * Copyright (c) 2014-2023 abel533@gmail.com * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ package com.github.pagehelper.dialect.helper; import com.github.pagehelper.Page; import com.github.pagehelper.dialect.AbstractHelperDialect; import com.github.pagehelper.util.MetaObjectUtil; import org.apache.ibatis.cache.CacheKey; import org.apache.ibatis.mapping.BoundSql; import org.apache.ibatis.mapping.MappedStatement; import org.apache.ibatis.mapping.ParameterMapping; import org.apache.ibatis.reflection.MetaObject; import java.util.ArrayList; import java.util.List; import java.util.Map; /** * GaussDB 方言 * * @author nieqiurong * @since 6.1.2 */ public class GaussDBDialect extends AbstractHelperDialect { @Override public Object processPageParameter(MappedStatement ms, Map paramMap, Page page, BoundSql boundSql, CacheKey pageKey) { paramMap.put(PAGEPARAMETER_FIRST, page.getStartRow()); paramMap.put(PAGEPARAMETER_SECOND, page.getPageSize()); pageKey.update(page.getStartRow()); pageKey.update(page.getPageSize()); if (boundSql.getParameterMappings() != null) { List newParameterMappings = new ArrayList(boundSql.getParameterMappings()); if (page.getStartRow() == 0) { newParameterMappings.add(new ParameterMapping.Builder(ms.getConfiguration(), PAGEPARAMETER_SECOND, int.class).build()); } else { newParameterMappings.add(new ParameterMapping.Builder(ms.getConfiguration(), PAGEPARAMETER_FIRST, long.class).build()); newParameterMappings.add(new ParameterMapping.Builder(ms.getConfiguration(), PAGEPARAMETER_SECOND, int.class).build()); } MetaObject metaObject = MetaObjectUtil.forObject(boundSql); metaObject.setValue("parameterMappings", newParameterMappings); } return paramMap; } /** * 构建 GaussDB分页查询语句 */ @Override public String getPageSql(String sql, Page page, CacheKey pageKey) { StringBuilder sqlBuilder = new StringBuilder(sql.length() + 14); sqlBuilder.append(sql); if (page.getStartRow() == 0) { sqlBuilder.append(" LIMIT ? "); } else { sqlBuilder.append(" LIMIT ?, ? "); } return sqlBuilder.toString(); } } ================================================ FILE: src/main/java/com/github/pagehelper/dialect/helper/HerdDBDialect.java ================================================ /* * The MIT License (MIT) * * Copyright (c) 2014-2023 abel533@gmail.com * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ package com.github.pagehelper.dialect.helper; import com.github.pagehelper.Page; import com.github.pagehelper.dialect.AbstractHelperDialect; import com.github.pagehelper.util.MetaObjectUtil; import org.apache.ibatis.cache.CacheKey; import org.apache.ibatis.mapping.BoundSql; import org.apache.ibatis.mapping.MappedStatement; import org.apache.ibatis.mapping.ParameterMapping; import org.apache.ibatis.reflection.MetaObject; import java.util.ArrayList; import java.util.List; import java.util.Map; /** * Support for HerdDB https://github.com/diennea/herddb. It is mostly the same as MySQL * @author Enrico Olivelli */ public class HerdDBDialect extends AbstractHelperDialect { @Override public Object processPageParameter(MappedStatement ms, Map paramMap, Page page, BoundSql boundSql, CacheKey pageKey) { paramMap.put(PAGEPARAMETER_FIRST, page.getStartRow()); paramMap.put(PAGEPARAMETER_SECOND, page.getPageSize()); pageKey.update(page.getStartRow()); pageKey.update(page.getPageSize()); if (boundSql.getParameterMappings() != null) { List newParameterMappings = new ArrayList(boundSql.getParameterMappings()); if (page.getStartRow() == 0) { newParameterMappings.add(new ParameterMapping.Builder(ms.getConfiguration(), PAGEPARAMETER_SECOND, int.class).build()); } else { newParameterMappings.add(new ParameterMapping.Builder(ms.getConfiguration(), PAGEPARAMETER_FIRST, long.class).build()); newParameterMappings.add(new ParameterMapping.Builder(ms.getConfiguration(), PAGEPARAMETER_SECOND, int.class).build()); } MetaObject metaObject = MetaObjectUtil.forObject(boundSql); metaObject.setValue("parameterMappings", newParameterMappings); } return paramMap; } @Override public String getPageSql(String sql, Page page, CacheKey pageKey) { StringBuilder sqlBuilder = new StringBuilder(sql.length() + 14); sqlBuilder.append(sql); if (page.getStartRow() == 0) { sqlBuilder.append("\n LIMIT ? "); } else { sqlBuilder.append("\n LIMIT ?, ? "); } return sqlBuilder.toString(); } } ================================================ FILE: src/main/java/com/github/pagehelper/dialect/helper/HsqldbDialect.java ================================================ /* * The MIT License (MIT) * * Copyright (c) 2014-2023 abel533@gmail.com * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ package com.github.pagehelper.dialect.helper; import com.github.pagehelper.Page; import com.github.pagehelper.dialect.AbstractHelperDialect; import com.github.pagehelper.util.MetaObjectUtil; import org.apache.ibatis.cache.CacheKey; import org.apache.ibatis.mapping.BoundSql; import org.apache.ibatis.mapping.MappedStatement; import org.apache.ibatis.mapping.ParameterMapping; import org.apache.ibatis.reflection.MetaObject; import java.util.ArrayList; import java.util.List; import java.util.Map; /** * @author liuzh */ public class HsqldbDialect extends AbstractHelperDialect { @Override public Object processPageParameter(MappedStatement ms, Map paramMap, Page page, BoundSql boundSql, CacheKey pageKey) { paramMap.put(PAGEPARAMETER_FIRST, page.getPageSize()); paramMap.put(PAGEPARAMETER_SECOND, page.getStartRow()); //处理pageKey pageKey.update(page.getPageSize()); pageKey.update(page.getStartRow()); //处理参数配置 if (boundSql.getParameterMappings() != null) { List newParameterMappings = new ArrayList(boundSql.getParameterMappings()); if (page.getPageSize() > 0) { newParameterMappings.add(new ParameterMapping.Builder(ms.getConfiguration(), PAGEPARAMETER_FIRST, int.class).build()); } if (page.getStartRow() > 0) { newParameterMappings.add(new ParameterMapping.Builder(ms.getConfiguration(), PAGEPARAMETER_SECOND, long.class).build()); } MetaObject metaObject = MetaObjectUtil.forObject(boundSql); metaObject.setValue("parameterMappings", newParameterMappings); } return paramMap; } @Override public String getPageSql(String sql, Page page, CacheKey pageKey) { StringBuilder sqlBuilder = new StringBuilder(sql.length() + 20); sqlBuilder.append(sql); if (page.getPageSize() > 0) { sqlBuilder.append("\n LIMIT ? "); } if (page.getStartRow() > 0) { sqlBuilder.append("\n OFFSET ? "); } return sqlBuilder.toString(); } } ================================================ FILE: src/main/java/com/github/pagehelper/dialect/helper/InformixDialect.java ================================================ /* * The MIT License (MIT) * * Copyright (c) 2014-2023 abel533@gmail.com * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ package com.github.pagehelper.dialect.helper; import com.github.pagehelper.Page; import com.github.pagehelper.dialect.AbstractHelperDialect; import com.github.pagehelper.util.MetaObjectUtil; import org.apache.ibatis.cache.CacheKey; import org.apache.ibatis.mapping.BoundSql; import org.apache.ibatis.mapping.MappedStatement; import org.apache.ibatis.mapping.ParameterMapping; import org.apache.ibatis.reflection.MetaObject; import java.util.ArrayList; import java.util.List; import java.util.Map; /** * @author liuzh */ public class InformixDialect extends AbstractHelperDialect { @Override public Object processPageParameter(MappedStatement ms, Map paramMap, Page page, BoundSql boundSql, CacheKey pageKey) { paramMap.put(PAGEPARAMETER_FIRST, page.getStartRow()); paramMap.put(PAGEPARAMETER_SECOND, page.getPageSize()); //处理pageKey pageKey.update(page.getStartRow()); pageKey.update(page.getPageSize()); //处理参数配置 if (boundSql.getParameterMappings() != null) { List newParameterMappings = new ArrayList(); if (page.getStartRow() > 0) { newParameterMappings.add(new ParameterMapping.Builder(ms.getConfiguration(), PAGEPARAMETER_FIRST, long.class).build()); } if (page.getPageSize() > 0) { newParameterMappings.add(new ParameterMapping.Builder(ms.getConfiguration(), PAGEPARAMETER_SECOND, int.class).build()); } newParameterMappings.addAll(boundSql.getParameterMappings()); MetaObject metaObject = MetaObjectUtil.forObject(boundSql); metaObject.setValue("parameterMappings", newParameterMappings); } return paramMap; } @Override public String getPageSql(String sql, Page page, CacheKey pageKey) { StringBuilder sqlBuilder = new StringBuilder(sql.length() + 40); sqlBuilder.append("SELECT "); if (page.getStartRow() > 0) { sqlBuilder.append(" SKIP ? "); } if (page.getPageSize() > 0) { sqlBuilder.append(" FIRST ? "); } sqlBuilder.append(" * FROM ( \n"); sqlBuilder.append(sql); sqlBuilder.append("\n ) TEMP_T "); return sqlBuilder.toString(); } } ================================================ FILE: src/main/java/com/github/pagehelper/dialect/helper/MySqlDialect.java ================================================ /* * The MIT License (MIT) * * Copyright (c) 2014-2023 abel533@gmail.com * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ package com.github.pagehelper.dialect.helper; import com.github.pagehelper.Page; import com.github.pagehelper.dialect.AbstractHelperDialect; import com.github.pagehelper.util.MetaObjectUtil; import org.apache.ibatis.cache.CacheKey; import org.apache.ibatis.mapping.BoundSql; import org.apache.ibatis.mapping.MappedStatement; import org.apache.ibatis.mapping.ParameterMapping; import org.apache.ibatis.reflection.MetaObject; import java.util.ArrayList; import java.util.List; import java.util.Map; /** * @author liuzh */ public class MySqlDialect extends AbstractHelperDialect { @Override public Object processPageParameter(MappedStatement ms, Map paramMap, Page page, BoundSql boundSql, CacheKey pageKey) { paramMap.put(PAGEPARAMETER_FIRST, page.getStartRow()); paramMap.put(PAGEPARAMETER_SECOND, page.getPageSize()); //处理pageKey pageKey.update(page.getStartRow()); pageKey.update(page.getPageSize()); //处理参数配置 if (boundSql.getParameterMappings() != null) { List newParameterMappings = new ArrayList(boundSql.getParameterMappings()); if (page.getStartRow() == 0) { newParameterMappings.add(new ParameterMapping.Builder(ms.getConfiguration(), PAGEPARAMETER_SECOND, int.class).build()); } else { newParameterMappings.add(new ParameterMapping.Builder(ms.getConfiguration(), PAGEPARAMETER_FIRST, long.class).build()); newParameterMappings.add(new ParameterMapping.Builder(ms.getConfiguration(), PAGEPARAMETER_SECOND, int.class).build()); } MetaObject metaObject = MetaObjectUtil.forObject(boundSql); metaObject.setValue("parameterMappings", newParameterMappings); } return paramMap; } @Override public String getPageSql(String sql, Page page, CacheKey pageKey) { StringBuilder sqlBuilder = new StringBuilder(sql.length() + 14); sqlBuilder.append(sql); if (page.getStartRow() == 0) { sqlBuilder.append("\n LIMIT ? "); } else { sqlBuilder.append("\n LIMIT ?, ? "); } return sqlBuilder.toString(); } } ================================================ FILE: src/main/java/com/github/pagehelper/dialect/helper/Oracle9iDialect.java ================================================ /* * The MIT License (MIT) * * Copyright (c) 2014-2023 abel533@gmail.com * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ package com.github.pagehelper.dialect.helper; import com.github.pagehelper.Page; import com.github.pagehelper.dialect.AbstractHelperDialect; import org.apache.ibatis.cache.CacheKey; import org.apache.ibatis.mapping.BoundSql; import org.apache.ibatis.mapping.MappedStatement; import java.util.Map; /** * 参考 *
    *
  • https://github.com/pagehelper/Mybatis-PageHelper/pull/476
  • *
  • https://github.com/hibernate/hibernate-orm/search?utf8=%E2%9C%93&q=rownum&type=
  • *
* @author liuzh */ public class Oracle9iDialect extends AbstractHelperDialect { @Override public Object processPageParameter(MappedStatement ms, Map paramMap, Page page, BoundSql boundSql, CacheKey pageKey) { paramMap.put(PAGEPARAMETER_FIRST, page.getEndRow()); paramMap.put(PAGEPARAMETER_SECOND, page.getStartRow()); //处理pageKey pageKey.update(page.getEndRow()); pageKey.update(page.getStartRow()); //处理参数配置 handleParameter(boundSql, ms, long.class, long.class); return paramMap; } @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 PAGEHELPER_ROW_ID FROM ( \n"); sqlBuilder.append(sql); sqlBuilder.append("\n ) TMP_PAGE WHERE ROWNUM <= ? "); sqlBuilder.append(" ) WHERE PAGEHELPER_ROW_ID > ? "); return sqlBuilder.toString(); } } ================================================ FILE: src/main/java/com/github/pagehelper/dialect/helper/OracleDialect.java ================================================ /* * The MIT License (MIT) * * Copyright (c) 2014-2023 abel533@gmail.com * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ package com.github.pagehelper.dialect.helper; import com.github.pagehelper.Page; import com.github.pagehelper.dialect.AbstractHelperDialect; import org.apache.ibatis.cache.CacheKey; import org.apache.ibatis.mapping.BoundSql; import org.apache.ibatis.mapping.MappedStatement; import java.util.Map; /** * @author liuzh */ public class OracleDialect extends AbstractHelperDialect { @Override public Object processPageParameter(MappedStatement ms, Map paramMap, Page page, BoundSql boundSql, CacheKey pageKey) { paramMap.put(PAGEPARAMETER_FIRST, page.getEndRow()); paramMap.put(PAGEPARAMETER_SECOND, page.getStartRow()); //处理pageKey pageKey.update(page.getEndRow()); pageKey.update(page.getStartRow()); //处理参数配置 handleParameter(boundSql, ms, long.class, long.class); return paramMap; } @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 PAGEHELPER_ROW_ID FROM ( \n"); sqlBuilder.append(sql); sqlBuilder.append("\n ) TMP_PAGE)"); sqlBuilder.append(" WHERE PAGEHELPER_ROW_ID <= ? AND PAGEHELPER_ROW_ID > ?"); return sqlBuilder.toString(); } } ================================================ FILE: src/main/java/com/github/pagehelper/dialect/helper/OscarDialect.java ================================================ /* * The MIT License (MIT) * * Copyright (c) 2014-2023 abel533@gmail.com * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ package com.github.pagehelper.dialect.helper; import com.github.pagehelper.Page; import com.github.pagehelper.dialect.AbstractHelperDialect; import com.github.pagehelper.util.MetaObjectUtil; import org.apache.ibatis.cache.CacheKey; import org.apache.ibatis.mapping.BoundSql; import org.apache.ibatis.mapping.MappedStatement; import org.apache.ibatis.mapping.ParameterMapping; import org.apache.ibatis.reflection.MetaObject; import java.util.ArrayList; import java.util.List; import java.util.Map; /** * */ public class OscarDialect extends AbstractHelperDialect { @Override public Object processPageParameter(MappedStatement ms, Map paramMap, Page page, BoundSql boundSql, CacheKey pageKey) { paramMap.put(PAGEPARAMETER_FIRST, page.getPageSize() ); paramMap.put(PAGEPARAMETER_SECOND, (int) page.getStartRow() ); //处理pageKey pageKey.update(page.getStartRow()); pageKey.update(page.getPageSize()); //处理参数配置 if (boundSql.getParameterMappings() != null) { List newParameterMappings = new ArrayList(boundSql.getParameterMappings()); if (page.getStartRow() == 0) { newParameterMappings.add(new ParameterMapping.Builder(ms.getConfiguration(), PAGEPARAMETER_FIRST, int.class).build()); } else { newParameterMappings.add(new ParameterMapping.Builder(ms.getConfiguration(), PAGEPARAMETER_FIRST, int.class).build()); newParameterMappings.add(new ParameterMapping.Builder(ms.getConfiguration(), PAGEPARAMETER_SECOND, int.class).build()); } MetaObject metaObject = MetaObjectUtil.forObject(boundSql); metaObject.setValue("parameterMappings", newParameterMappings); } return paramMap; } @Override public String getPageSql(String sql, Page page, CacheKey pageKey) { StringBuilder sqlBuilder = new StringBuilder(sql.length() + 14); sqlBuilder.append(sql); if (page.getStartRow() == 0) { sqlBuilder.append("\n LIMIT ? "); } else { sqlBuilder.append("\n LIMIT ? OFFSET ? "); } return sqlBuilder.toString(); } } ================================================ FILE: src/main/java/com/github/pagehelper/dialect/helper/PostgreSqlDialect.java ================================================ /* * The MIT License (MIT) * * Copyright (c) 2014-2023 abel533@gmail.com * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ package com.github.pagehelper.dialect.helper; import com.github.pagehelper.Page; import com.github.pagehelper.dialect.AbstractHelperDialect; import com.github.pagehelper.util.MetaObjectUtil; import org.apache.ibatis.cache.CacheKey; import org.apache.ibatis.mapping.BoundSql; import org.apache.ibatis.mapping.MappedStatement; import org.apache.ibatis.mapping.ParameterMapping; import org.apache.ibatis.reflection.MetaObject; import java.util.ArrayList; import java.util.List; import java.util.Map; /** * PostgreSQL 方言. * * @author liym * @since 2021-02-06 */ public class PostgreSqlDialect extends AbstractHelperDialect { @Override public Object processPageParameter(MappedStatement ms, Map paramMap, Page page, BoundSql boundSql, CacheKey pageKey) { paramMap.put(PAGEPARAMETER_SECOND, page.getPageSize()); paramMap.put(PAGEPARAMETER_FIRST, page.getStartRow()); //处理pageKey pageKey.update(page.getPageSize()); pageKey.update(page.getStartRow()); //处理参数配置 if (boundSql.getParameterMappings() != null) { List newParameterMappings = new ArrayList(boundSql.getParameterMappings()); if (page.getStartRow() == 0) { newParameterMappings.add(new ParameterMapping.Builder(ms.getConfiguration(), PAGEPARAMETER_SECOND, int.class).build()); } else { newParameterMappings.add(new ParameterMapping.Builder(ms.getConfiguration(), PAGEPARAMETER_SECOND, int.class).build()); newParameterMappings.add(new ParameterMapping.Builder(ms.getConfiguration(), PAGEPARAMETER_FIRST, long.class).build()); } MetaObject metaObject = MetaObjectUtil.forObject(boundSql); metaObject.setValue("parameterMappings", newParameterMappings); } return paramMap; } /** * 构建 PostgreSQL分页查询语句 */ @Override public String getPageSql(String sql, Page page, CacheKey pageKey) { StringBuilder sqlStr = new StringBuilder(sql.length() + 17); sqlStr.append(sql); if (page.getStartRow() == 0) { sqlStr.append(" LIMIT ?"); } else { sqlStr.append(" LIMIT ? OFFSET ?"); } return sqlStr.toString(); } } ================================================ FILE: src/main/java/com/github/pagehelper/dialect/helper/SqlServer2012Dialect.java ================================================ /* * The MIT License (MIT) * * Copyright (c) 2014-2023 abel533@gmail.com * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ package com.github.pagehelper.dialect.helper; import com.github.pagehelper.Page; import org.apache.ibatis.cache.CacheKey; import org.apache.ibatis.mapping.BoundSql; import org.apache.ibatis.mapping.MappedStatement; import java.util.Map; /** * @author liuzh */ public class SqlServer2012Dialect extends SqlServerDialect { @Override public Object processPageParameter(MappedStatement ms, Map paramMap, Page page, BoundSql boundSql, CacheKey pageKey) { paramMap.put(PAGEPARAMETER_FIRST, page.getStartRow()); paramMap.put(PAGEPARAMETER_SECOND, page.getPageSize()); //处理pageKey pageKey.update(page.getStartRow()); pageKey.update(page.getPageSize()); //处理参数配置 handleParameter(boundSql, ms, long.class, int.class); return paramMap; } @Override public String getPageSql(String sql, Page page, CacheKey pageKey) { StringBuilder sqlBuilder = new StringBuilder(sql.length() + 64); sqlBuilder.append(sql); sqlBuilder.append("\n OFFSET ? ROWS FETCH NEXT ? ROWS ONLY "); pageKey.update(page.getPageSize()); return sqlBuilder.toString(); } } ================================================ FILE: src/main/java/com/github/pagehelper/dialect/helper/SqlServerDialect.java ================================================ /* * The MIT License (MIT) * * Copyright (c) 2014-2023 abel533@gmail.com * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ package com.github.pagehelper.dialect.helper; import com.github.pagehelper.Page; import com.github.pagehelper.cache.Cache; import com.github.pagehelper.cache.CacheFactory; import com.github.pagehelper.dialect.AbstractHelperDialect; import com.github.pagehelper.dialect.ReplaceSql; import com.github.pagehelper.dialect.replace.RegexWithNolockReplaceSql; import com.github.pagehelper.dialect.replace.SimpleWithNolockReplaceSql; import com.github.pagehelper.parser.SqlServerSqlParser; import com.github.pagehelper.parser.defaults.DefaultSqlServerSqlParser; import com.github.pagehelper.util.ClassUtil; import com.github.pagehelper.util.StringUtil; import org.apache.ibatis.cache.CacheKey; import org.apache.ibatis.mapping.BoundSql; import org.apache.ibatis.mapping.MappedStatement; import org.apache.ibatis.session.RowBounds; import java.util.Map; import java.util.Properties; /** * @author liuzh */ public class SqlServerDialect extends AbstractHelperDialect { protected SqlServerSqlParser sqlServerSqlParser; protected Cache CACHE_COUNTSQL; protected Cache CACHE_PAGESQL; protected ReplaceSql replaceSql; @Override public String getCountSql(MappedStatement ms, BoundSql boundSql, Object parameterObject, RowBounds rowBounds, CacheKey countKey) { String sql = boundSql.getSql(); String cacheSql = CACHE_COUNTSQL.get(sql); if (cacheSql != null) { return cacheSql; } else { cacheSql = sql; } cacheSql = replaceSql.replace(cacheSql); cacheSql = countSqlParser.getSmartCountSql(cacheSql); cacheSql = replaceSql.restore(cacheSql); CACHE_COUNTSQL.put(sql, cacheSql); return cacheSql; } @Override public Object processPageParameter(MappedStatement ms, Map paramMap, Page page, BoundSql boundSql, CacheKey pageKey) { return paramMap; } @Override public String getPageSql(String sql, Page page, CacheKey pageKey) { //处理pageKey pageKey.update(page.getStartRow()); pageKey.update(page.getPageSize()); String cacheSql = CACHE_PAGESQL.get(sql); if (cacheSql == null) { cacheSql = sql; cacheSql = replaceSql.replace(cacheSql); cacheSql = sqlServerSqlParser.convertToPageSql(cacheSql, null, null); cacheSql = replaceSql.restore(cacheSql); CACHE_PAGESQL.put(sql, cacheSql); } cacheSql = cacheSql.replace(String.valueOf(Long.MIN_VALUE), String.valueOf(page.getStartRow())); cacheSql = cacheSql.replace(String.valueOf(Long.MAX_VALUE), String.valueOf(page.getPageSize())); return cacheSql; } /** * 分页查询,pageHelper转换SQL时报错with(nolock)不识别的问题, * 重写父类AbstractHelperDialect.getPageSql转换出错的方法。 * 1. this.replaceSql.replace(sql);先转换成假的表名 * 2. 然后进行SQL转换 * 3. this.replaceSql.restore(sql);最后再恢复成真的with(nolock) */ @Override public String getPageSql(MappedStatement ms, BoundSql boundSql, Object parameterObject, RowBounds rowBounds, CacheKey pageKey) { String sql = boundSql.getSql(); Page page = this.getLocalPage(); String orderBy = page.getOrderBy(); if (StringUtil.isNotEmpty(orderBy)) { pageKey.update(orderBy); sql = this.replaceSql.replace(sql); sql = orderBySqlParser.converToOrderBySql(sql, orderBy); sql = this.replaceSql.restore(sql); } return page.isOrderByOnly() ? sql : this.getPageSql(sql, page, pageKey); } @Override public void setProperties(Properties properties) { super.setProperties(properties); this.sqlServerSqlParser = ClassUtil.newInstance(properties.getProperty("sqlServerSqlParser"), SqlServerSqlParser.class, properties, DefaultSqlServerSqlParser::new); String replaceSql = properties.getProperty("replaceSql"); if (StringUtil.isEmpty(replaceSql) || "regex".equalsIgnoreCase(replaceSql)) { this.replaceSql = new RegexWithNolockReplaceSql(); } else if ("simple".equalsIgnoreCase(replaceSql)) { this.replaceSql = new SimpleWithNolockReplaceSql(); } else { this.replaceSql = ClassUtil.newInstance(replaceSql, properties); } String sqlCacheClass = properties.getProperty("sqlCacheClass"); if (StringUtil.isNotEmpty(sqlCacheClass) && !sqlCacheClass.equalsIgnoreCase("false")) { CACHE_COUNTSQL = CacheFactory.createCache(sqlCacheClass, "count", properties); CACHE_PAGESQL = CacheFactory.createCache(sqlCacheClass, "page", properties); } else { CACHE_COUNTSQL = CacheFactory.createCache(null, "count", properties); CACHE_PAGESQL = CacheFactory.createCache(null, "page", properties); } } } ================================================ FILE: src/main/java/com/github/pagehelper/dialect/helper/XuguDialect.java ================================================ /* * The MIT License (MIT) * * Copyright (c) 2014-2017 abel533@gmail.com * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ package com.github.pagehelper.dialect.helper; import com.github.pagehelper.Page; import com.github.pagehelper.dialect.AbstractHelperDialect; import com.github.pagehelper.util.MetaObjectUtil; import org.apache.ibatis.cache.CacheKey; import org.apache.ibatis.mapping.BoundSql; import org.apache.ibatis.mapping.MappedStatement; import org.apache.ibatis.mapping.ParameterMapping; import org.apache.ibatis.reflection.MetaObject; import java.util.ArrayList; import java.util.List; import java.util.Map; /** * @author liuzh */ public class XuguDialect extends AbstractHelperDialect { @Override public Object processPageParameter(MappedStatement ms, Map paramMap, Page page, BoundSql boundSql, CacheKey pageKey) { paramMap.put(PAGEPARAMETER_FIRST, page.getStartRow()); paramMap.put(PAGEPARAMETER_SECOND, page.getPageSize()); //处理pageKey pageKey.update(page.getStartRow()); pageKey.update(page.getPageSize()); //处理参数配置 if (boundSql.getParameterMappings() != null) { List newParameterMappings = new ArrayList(boundSql.getParameterMappings()); if (page.getStartRow() == 0) { newParameterMappings.add(new ParameterMapping.Builder(ms.getConfiguration(), PAGEPARAMETER_SECOND, int.class).build()); } else { newParameterMappings.add(new ParameterMapping.Builder(ms.getConfiguration(), PAGEPARAMETER_FIRST, long.class).build()); newParameterMappings.add(new ParameterMapping.Builder(ms.getConfiguration(), PAGEPARAMETER_SECOND, int.class).build()); } MetaObject metaObject = MetaObjectUtil.forObject(boundSql); metaObject.setValue("parameterMappings", newParameterMappings); } return paramMap; } @Override public String getPageSql(String sql, Page page, CacheKey pageKey) { StringBuilder sqlBuilder = new StringBuilder(sql.length() + 14); sqlBuilder.append(sql); if (page.getStartRow() == 0) { sqlBuilder.append("\n LIMIT ? "); } else { sqlBuilder.append("\n LIMIT ?, ? "); } return sqlBuilder.toString(); } } ================================================ FILE: src/main/java/com/github/pagehelper/dialect/replace/RegexWithNolockReplaceSql.java ================================================ /* * The MIT License (MIT) * * Copyright (c) 2014-2023 abel533@gmail.com * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ package com.github.pagehelper.dialect.replace; import com.github.pagehelper.dialect.ReplaceSql; /** * 正则处理 with(nolock),转换为一个 table_PAGEWITHNOLOCK * * @author liuzh * @since 2017/8/23. */ public class RegexWithNolockReplaceSql implements ReplaceSql { //with(nolock) protected String WITHNOLOCK = ", PAGEWITHNOLOCK"; @Override public String replace(String sql) { return sql.replaceAll("((?i)\\s*(\\w+)\\s*with\\s*\\(\\s*nolock\\s*\\))", " $2_PAGEWITHNOLOCK"); } @Override public String restore(String sql) { return sql.replaceAll("\\s*(\\w*?)_PAGEWITHNOLOCK", " $1 WITH(NOLOCK)"); } } ================================================ FILE: src/main/java/com/github/pagehelper/dialect/replace/SimpleWithNolockReplaceSql.java ================================================ /* * The MIT License (MIT) * * Copyright (c) 2014-2023 abel533@gmail.com * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ package com.github.pagehelper.dialect.replace; import com.github.pagehelper.dialect.ReplaceSql; /** * 简单处理 with(nolock) * * @author liuzh * @since 2017/8/23. */ public class SimpleWithNolockReplaceSql implements ReplaceSql { //with(nolock) protected String WITHNOLOCK = ", PAGEWITHNOLOCK"; @Override public String replace(String sql) { return sql.replaceAll("((?i)with\\s*\\(nolock\\))", WITHNOLOCK); } @Override public String restore(String sql) { return sql.replaceAll(WITHNOLOCK, " with(nolock)"); } } ================================================ FILE: src/main/java/com/github/pagehelper/dialect/rowbounds/Db2RowBoundsDialect.java ================================================ /* * The MIT License (MIT) * * Copyright (c) 2014-2023 abel533@gmail.com * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ package com.github.pagehelper.dialect.rowbounds; import com.github.pagehelper.dialect.AbstractRowBoundsDialect; import org.apache.ibatis.cache.CacheKey; import org.apache.ibatis.session.RowBounds; /** * db2 基于 RowBounds 的分页 * * @author liuzh */ public class Db2RowBoundsDialect extends AbstractRowBoundsDialect { @Override public String getPageSql(String sql, RowBounds rowBounds, CacheKey pageKey) { int startRow = rowBounds.getOffset() + 1; int endRow = rowBounds.getOffset() + rowBounds.getLimit(); StringBuilder sqlBuilder = new StringBuilder(sql.length() + 120); sqlBuilder.append("SELECT * FROM (SELECT TMP_PAGE.*,ROWNUMBER() OVER() AS PAGEHELPER_ROW_ID FROM ( \n"); sqlBuilder.append(sql); sqlBuilder.append("\n ) AS TMP_PAGE) TMP_PAGE WHERE PAGEHELPER_ROW_ID BETWEEN "); sqlBuilder.append(startRow); sqlBuilder.append(" AND "); sqlBuilder.append(endRow); pageKey.update(startRow); pageKey.update(endRow); return sqlBuilder.toString(); } } ================================================ FILE: src/main/java/com/github/pagehelper/dialect/rowbounds/GaussDBRowBoundsDialect.java ================================================ /* * The MIT License (MIT) * * Copyright (c) 2014-2023 abel533@gmail.com * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ package com.github.pagehelper.dialect.rowbounds; import com.github.pagehelper.dialect.AbstractRowBoundsDialect; import org.apache.ibatis.cache.CacheKey; import org.apache.ibatis.session.RowBounds; /** * GaussDB 基于 RowBounds 的分页. * * @author nieqiurong * @since 6.1.2 */ public class GaussDBRowBoundsDialect extends AbstractRowBoundsDialect { /** * 构建 GaussDB分页查询语句 */ @Override public String getPageSql(String sql, RowBounds rowBounds, CacheKey pageKey) { StringBuilder sqlBuilder = new StringBuilder(sql.length() + 14); sqlBuilder.append(sql); if (rowBounds.getOffset() == 0) { sqlBuilder.append(" LIMIT "); sqlBuilder.append(rowBounds.getLimit()); } else { sqlBuilder.append(" LIMIT "); sqlBuilder.append(rowBounds.getOffset()); sqlBuilder.append(","); sqlBuilder.append(rowBounds.getLimit()); pageKey.update(rowBounds.getOffset()); } pageKey.update(rowBounds.getLimit()); return sqlBuilder.toString(); } } ================================================ FILE: src/main/java/com/github/pagehelper/dialect/rowbounds/HerdDBRowBoundsDialect.java ================================================ /* * The MIT License (MIT) * * Copyright (c) 2014-2023 abel533@gmail.com * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ package com.github.pagehelper.dialect.rowbounds; import com.github.pagehelper.dialect.AbstractRowBoundsDialect; import org.apache.ibatis.cache.CacheKey; import org.apache.ibatis.session.RowBounds; /** * HerdDB 基于 RowBounds 的分页 * * @author Enrico Olivelli */ public class HerdDBRowBoundsDialect extends AbstractRowBoundsDialect { @Override public String getPageSql(String sql, RowBounds rowBounds, CacheKey pageKey) { StringBuilder sqlBuilder = new StringBuilder(sql.length() + 14); sqlBuilder.append(sql); if (rowBounds.getOffset() == 0) { sqlBuilder.append("\n LIMIT "); sqlBuilder.append(rowBounds.getLimit()); } else { sqlBuilder.append("\n LIMIT "); sqlBuilder.append(rowBounds.getOffset()); sqlBuilder.append(","); sqlBuilder.append(rowBounds.getLimit()); pageKey.update(rowBounds.getOffset()); } pageKey.update(rowBounds.getLimit()); return sqlBuilder.toString(); } } ================================================ FILE: src/main/java/com/github/pagehelper/dialect/rowbounds/HsqldbRowBoundsDialect.java ================================================ /* * The MIT License (MIT) * * Copyright (c) 2014-2023 abel533@gmail.com * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ package com.github.pagehelper.dialect.rowbounds; import com.github.pagehelper.dialect.AbstractRowBoundsDialect; import org.apache.ibatis.cache.CacheKey; import org.apache.ibatis.session.RowBounds; /** * hsqldb 基于 RowBounds 的分页 * * @author liuzh */ public class HsqldbRowBoundsDialect extends AbstractRowBoundsDialect { @Override public String getPageSql(String sql, RowBounds rowBounds, CacheKey pageKey) { StringBuilder sqlBuilder = new StringBuilder(sql.length() + 20); sqlBuilder.append(sql); if (rowBounds.getLimit() > 0) { sqlBuilder.append("\n LIMIT "); sqlBuilder.append(rowBounds.getLimit()); pageKey.update(rowBounds.getLimit()); } if (rowBounds.getOffset() > 0) { sqlBuilder.append("\n OFFSET "); sqlBuilder.append(rowBounds.getOffset()); pageKey.update(rowBounds.getOffset()); } return sqlBuilder.toString(); } } ================================================ FILE: src/main/java/com/github/pagehelper/dialect/rowbounds/InformixRowBoundsDialect.java ================================================ /* * The MIT License (MIT) * * Copyright (c) 2014-2023 abel533@gmail.com * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ package com.github.pagehelper.dialect.rowbounds; import com.github.pagehelper.dialect.AbstractRowBoundsDialect; import org.apache.ibatis.cache.CacheKey; import org.apache.ibatis.session.RowBounds; /** * informix 基于 RowBounds 的分页 * * @author liuzh */ public class InformixRowBoundsDialect extends AbstractRowBoundsDialect { @Override public String getPageSql(String sql, RowBounds rowBounds, CacheKey pageKey) { StringBuilder sqlBuilder = new StringBuilder(sql.length() + 40); sqlBuilder.append("SELECT "); if (rowBounds.getOffset() > 0) { sqlBuilder.append(" SKIP "); sqlBuilder.append(rowBounds.getOffset()); pageKey.update(rowBounds.getOffset()); } if (rowBounds.getLimit() > 0) { sqlBuilder.append(" FIRST "); sqlBuilder.append(rowBounds.getLimit()); pageKey.update(rowBounds.getLimit()); } sqlBuilder.append(" * FROM ( \n"); sqlBuilder.append(sql); sqlBuilder.append("\n ) TEMP_T"); return sqlBuilder.toString(); } } ================================================ FILE: src/main/java/com/github/pagehelper/dialect/rowbounds/MySqlRowBoundsDialect.java ================================================ /* * The MIT License (MIT) * * Copyright (c) 2014-2023 abel533@gmail.com * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ package com.github.pagehelper.dialect.rowbounds; import com.github.pagehelper.dialect.AbstractRowBoundsDialect; import org.apache.ibatis.cache.CacheKey; import org.apache.ibatis.session.RowBounds; /** * mysql 基于 RowBounds 的分页 * * @author liuzh */ public class MySqlRowBoundsDialect extends AbstractRowBoundsDialect { @Override public String getPageSql(String sql, RowBounds rowBounds, CacheKey pageKey) { StringBuilder sqlBuilder = new StringBuilder(sql.length() + 14); sqlBuilder.append(sql); if (rowBounds.getOffset() == 0) { sqlBuilder.append("\n LIMIT "); sqlBuilder.append(rowBounds.getLimit()); } else { sqlBuilder.append("\n LIMIT "); sqlBuilder.append(rowBounds.getOffset()); sqlBuilder.append(","); sqlBuilder.append(rowBounds.getLimit()); pageKey.update(rowBounds.getOffset()); } pageKey.update(rowBounds.getLimit()); return sqlBuilder.toString(); } } ================================================ FILE: src/main/java/com/github/pagehelper/dialect/rowbounds/OracleRowBoundsDialect.java ================================================ /* * The MIT License (MIT) * * Copyright (c) 2014-2023 abel533@gmail.com * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ package com.github.pagehelper.dialect.rowbounds; import com.github.pagehelper.dialect.AbstractRowBoundsDialect; import org.apache.ibatis.cache.CacheKey; import org.apache.ibatis.session.RowBounds; /** * oracle 基于 RowBounds 的分页 * * @author liuzh */ public class OracleRowBoundsDialect extends AbstractRowBoundsDialect { @Override public String getPageSql(String sql, RowBounds rowBounds, CacheKey pageKey) { int startRow = rowBounds.getOffset(); int endRow = rowBounds.getOffset() + rowBounds.getLimit(); StringBuilder sqlBuilder = new StringBuilder(sql.length() + 120); if (startRow > 0) { sqlBuilder.append("SELECT * FROM ( "); } if (endRow > 0) { sqlBuilder.append(" SELECT TMP_PAGE.*, ROWNUM PAGEHELPER_ROW_ID FROM ( "); } sqlBuilder.append("\n"); sqlBuilder.append(sql); sqlBuilder.append("\n"); if (endRow > 0) { sqlBuilder.append(" ) TMP_PAGE WHERE ROWNUM <= "); sqlBuilder.append(endRow); pageKey.update(endRow); } if (startRow > 0) { sqlBuilder.append(" ) WHERE PAGEHELPER_ROW_ID > "); sqlBuilder.append(startRow); pageKey.update(startRow); } return sqlBuilder.toString(); } } ================================================ FILE: src/main/java/com/github/pagehelper/dialect/rowbounds/PostgreSqlRowBoundsDialect.java ================================================ /* * The MIT License (MIT) * * Copyright (c) 2014-2023 abel533@gmail.com * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ package com.github.pagehelper.dialect.rowbounds; import com.github.pagehelper.dialect.AbstractRowBoundsDialect; import org.apache.ibatis.cache.CacheKey; import org.apache.ibatis.session.RowBounds; /** * PostgreSQL 基于 RowBounds 的分页. * * @author liym * @since 2021-02-06 19:31 新建 */ public class PostgreSqlRowBoundsDialect extends AbstractRowBoundsDialect { /** * 构建 PostgreSQL分页查询语句 */ @Override public String getPageSql(String sql, RowBounds rowBounds, CacheKey pageKey) { StringBuilder sqlStr = new StringBuilder(sql.length() + 17); sqlStr.append(sql); if (rowBounds.getOffset() == 0) { sqlStr.append(" LIMIT "); sqlStr.append(rowBounds.getLimit()); } else { sqlStr.append(" LIMIT "); sqlStr.append(rowBounds.getLimit()); sqlStr.append(" OFFSET "); sqlStr.append(rowBounds.getOffset()); pageKey.update(rowBounds.getOffset()); } pageKey.update(rowBounds.getLimit()); return sqlStr.toString(); } } ================================================ FILE: src/main/java/com/github/pagehelper/dialect/rowbounds/SqlServer2012RowBoundsDialect.java ================================================ /* * The MIT License (MIT) * * Copyright (c) 2014-2023 abel533@gmail.com * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ package com.github.pagehelper.dialect.rowbounds; import org.apache.ibatis.cache.CacheKey; import org.apache.ibatis.session.RowBounds; /** * sqlserver2012 基于 RowBounds 的分页 * * @author liuzh */ public class SqlServer2012RowBoundsDialect extends SqlServerRowBoundsDialect { @Override public String getPageSql(String sql, RowBounds rowBounds, CacheKey pageKey) { StringBuilder sqlBuilder = new StringBuilder(sql.length() + 14); sqlBuilder.append(sql); sqlBuilder.append("\n OFFSET "); sqlBuilder.append(rowBounds.getOffset()); sqlBuilder.append(" ROWS "); pageKey.update(rowBounds.getOffset()); sqlBuilder.append(" FETCH NEXT "); sqlBuilder.append(rowBounds.getLimit()); sqlBuilder.append(" ROWS ONLY"); pageKey.update(rowBounds.getLimit()); return sqlBuilder.toString(); } } ================================================ FILE: src/main/java/com/github/pagehelper/dialect/rowbounds/SqlServerRowBoundsDialect.java ================================================ /* * The MIT License (MIT) * * Copyright (c) 2014-2023 abel533@gmail.com * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ package com.github.pagehelper.dialect.rowbounds; import com.github.pagehelper.dialect.AbstractRowBoundsDialect; import com.github.pagehelper.dialect.ReplaceSql; import com.github.pagehelper.dialect.replace.RegexWithNolockReplaceSql; import com.github.pagehelper.dialect.replace.SimpleWithNolockReplaceSql; import com.github.pagehelper.parser.SqlServerSqlParser; import com.github.pagehelper.parser.defaults.DefaultSqlServerSqlParser; import com.github.pagehelper.util.ClassUtil; import com.github.pagehelper.util.StringUtil; import org.apache.ibatis.cache.CacheKey; import org.apache.ibatis.mapping.BoundSql; import org.apache.ibatis.mapping.MappedStatement; import org.apache.ibatis.session.RowBounds; import java.util.Properties; /** * sqlserver 基于 RowBounds 的分页 * * @author liuzh */ public class SqlServerRowBoundsDialect extends AbstractRowBoundsDialect { protected SqlServerSqlParser sqlServerSqlParser; protected ReplaceSql replaceSql; @Override public String getCountSql(MappedStatement ms, BoundSql boundSql, Object parameterObject, RowBounds rowBounds, CacheKey countKey) { String sql = boundSql.getSql(); sql = replaceSql.replace(sql); sql = countSqlParser.getSmartCountSql(sql); sql = replaceSql.restore(sql); return sql; } @Override public String getPageSql(String sql, RowBounds rowBounds, CacheKey pageKey) { //处理pageKey pageKey.update(rowBounds.getOffset()); pageKey.update(rowBounds.getLimit()); sql = replaceSql.replace(sql); sql = sqlServerSqlParser.convertToPageSql(sql, null, null); sql = replaceSql.restore(sql); sql = sql.replace(String.valueOf(Long.MIN_VALUE), String.valueOf(rowBounds.getOffset())); sql = sql.replace(String.valueOf(Long.MAX_VALUE), String.valueOf(rowBounds.getLimit())); return sql; } @Override public void setProperties(Properties properties) { super.setProperties(properties); this.sqlServerSqlParser = ClassUtil.newInstance(properties.getProperty("sqlServerSqlParser"), SqlServerSqlParser.class, properties, DefaultSqlServerSqlParser::new); String replaceSql = properties.getProperty("replaceSql"); if (StringUtil.isEmpty(replaceSql) || "simple".equalsIgnoreCase(replaceSql)) { this.replaceSql = new SimpleWithNolockReplaceSql(); } else if ("regex".equalsIgnoreCase(replaceSql)) { this.replaceSql = new RegexWithNolockReplaceSql(); } else { this.replaceSql = ClassUtil.newInstance(replaceSql, properties); } } } ================================================ FILE: src/main/java/com/github/pagehelper/dialect/rowbounds/XuguRowBoundsDialect.java ================================================ /* * The MIT License (MIT) * * Copyright (c) 2014-2017 abel533@gmail.com * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ package com.github.pagehelper.dialect.rowbounds; import com.github.pagehelper.dialect.AbstractRowBoundsDialect; import org.apache.ibatis.cache.CacheKey; import org.apache.ibatis.session.RowBounds; /** * mysql 基于 RowBounds 的分页 * * @author liuzh */ public class XuguRowBoundsDialect extends AbstractRowBoundsDialect { @Override public String getPageSql(String sql, RowBounds rowBounds, CacheKey pageKey) { StringBuilder sqlBuilder = new StringBuilder(sql.length() + 14); sqlBuilder.append(sql); if (rowBounds.getOffset() == 0) { sqlBuilder.append("\n LIMIT "); sqlBuilder.append(rowBounds.getLimit()); } else { sqlBuilder.append("\n LIMIT "); sqlBuilder.append(rowBounds.getOffset()); sqlBuilder.append(","); sqlBuilder.append(rowBounds.getLimit()); pageKey.update(rowBounds.getOffset()); } pageKey.update(rowBounds.getLimit()); return sqlBuilder.toString(); } } ================================================ FILE: src/main/java/com/github/pagehelper/dialect/rowbounds/package-info.java ================================================ /* * The MIT License (MIT) * * Copyright (c) 2014-2023 abel533@gmail.com * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ /** * 当前包中的实现属于示例,也可以使用,但是以后不会再支持更多数据库 */ package com.github.pagehelper.dialect.rowbounds; ================================================ FILE: src/main/java/com/github/pagehelper/page/PageAutoDialect.java ================================================ /* * The MIT License (MIT) * * Copyright (c) 2014-2023 abel533@gmail.com * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ package com.github.pagehelper.page; import com.github.pagehelper.AutoDialect; import com.github.pagehelper.Dialect; import com.github.pagehelper.PageException; import com.github.pagehelper.dialect.AbstractHelperDialect; import com.github.pagehelper.dialect.auto.*; import com.github.pagehelper.dialect.helper.*; import com.github.pagehelper.util.ClassUtil; import com.github.pagehelper.util.StringUtil; import org.apache.ibatis.mapping.MappedStatement; import javax.sql.DataSource; import java.util.LinkedHashMap; import java.util.Map; import java.util.Properties; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.locks.ReentrantLock; /** * 基础方言信息 * * @author liuzh */ public class PageAutoDialect { private static Map> dialectAliasMap = new LinkedHashMap<>(); private static Map> autoDialectMap = new LinkedHashMap<>(); public static void registerDialectAlias(String alias, Class dialectClass) { dialectAliasMap.put(alias, dialectClass); } static { //注册别名 registerDialectAlias("hsqldb", HsqldbDialect.class); registerDialectAlias("h2", HsqldbDialect.class); registerDialectAlias("phoenix", HsqldbDialect.class); registerDialectAlias("postgresql", PostgreSqlDialect.class); registerDialectAlias("mysql", MySqlDialect.class); registerDialectAlias("mariadb", MySqlDialect.class); registerDialectAlias("sqlite", MySqlDialect.class); registerDialectAlias("herddb", HerdDBDialect.class); registerDialectAlias("oracle", OracleDialect.class); registerDialectAlias("oracle9i", Oracle9iDialect.class); registerDialectAlias("db2", Db2Dialect.class); registerDialectAlias("as400", AS400Dialect.class); registerDialectAlias("informix", InformixDialect.class); //解决 informix-sqli #129,仍然保留上面的 registerDialectAlias("informix-sqli", InformixDialect.class); registerDialectAlias("sqlserver", SqlServerDialect.class); registerDialectAlias("sqlserver2012", SqlServer2012Dialect.class); registerDialectAlias("derby", SqlServer2012Dialect.class); //达梦数据库,https://github.com/mybatis-book/book/issues/43 registerDialectAlias("dm", OracleDialect.class); //阿里云PPAS数据库,https://github.com/pagehelper/Mybatis-PageHelper/issues/281 registerDialectAlias("edb", OracleDialect.class); //神通数据库 registerDialectAlias("oscar", OscarDialect.class); registerDialectAlias("clickhouse", MySqlDialect.class); //瀚高数据库 registerDialectAlias("highgo", HsqldbDialect.class); //虚谷数据库 registerDialectAlias("xugu", HsqldbDialect.class); registerDialectAlias("impala", HsqldbDialect.class); registerDialectAlias("firebirdsql", FirebirdDialect.class); //人大金仓数据库 registerDialectAlias("kingbase", PostgreSqlDialect.class); // 人大金仓新版本kingbase8 registerDialectAlias("kingbase8", PostgreSqlDialect.class); //行云数据库 registerDialectAlias("xcloud", CirroDataDialect.class); //openGauss数据库 registerDialectAlias("opengauss", PostgreSqlDialect.class); registerDialectAlias("gaussdb", GaussDBDialect.class); registerDialectAlias("sundb", OracleDialect.class); //注册 AutoDialect //想要实现和以前版本相同的效果时,可以配置 autoDialectClass=old registerAutoDialectAlias("old", DefaultAutoDialect.class); registerAutoDialectAlias("hikari", HikariAutoDialect.class); registerAutoDialectAlias("druid", DruidAutoDialect.class); registerAutoDialectAlias("tomcat-jdbc", TomcatAutoDialect.class); registerAutoDialectAlias("dbcp", DbcpAutoDialect.class); registerAutoDialectAlias("c3p0", C3P0AutoDialect.class); //不配置时,默认使用 DataSourceNegotiationAutoDialect registerAutoDialectAlias("default", DataSourceNegotiationAutoDialect.class); } public static void registerAutoDialectAlias(String alias, Class autoDialectClass) { autoDialectMap.put(alias, autoDialectClass); } /** * 自动获取dialect,如果没有setProperties或setSqlUtilConfig,也可以正常进行 */ private boolean autoDialect = true; /** * 属性配置 */ private Properties properties; /** * 缓存 dialect 实现,key 有两种,分别为 jdbcurl 和 dialectClassName */ private Map urlDialectMap = new ConcurrentHashMap(); private ReentrantLock lock = new ReentrantLock(); private AbstractHelperDialect delegate; private ThreadLocal dialectThreadLocal = new ThreadLocal(); private AutoDialect autoDialectDelegate; public static String fromJdbcUrl(String jdbcUrl) { final String url = jdbcUrl.toLowerCase(); for (String dialect : dialectAliasMap.keySet()) { if (url.contains(":" + dialect.toLowerCase() + ":")) { return dialect; } } return null; } //获取当前的代理对象 public AbstractHelperDialect getDelegate() { if (delegate != null) { return delegate; } return dialectThreadLocal.get(); } //移除代理对象 public void clearDelegate() { dialectThreadLocal.remove(); } public AbstractHelperDialect getDialectThreadLocal() { return dialectThreadLocal.get(); } public void setDialectThreadLocal(AbstractHelperDialect delegate) { this.dialectThreadLocal.set(delegate); } /** * 反射类 * * @param className * @return * @throws Exception */ public static Class resloveDialectClass(String className) throws Exception { if (dialectAliasMap.containsKey(className.toLowerCase())) { return dialectAliasMap.get(className.toLowerCase()); } else { return Class.forName(className); } } /** * 初始化 helper * * @param dialectClass * @param properties */ public static AbstractHelperDialect instanceDialect(String dialectClass, Properties properties) { AbstractHelperDialect dialect; if (StringUtil.isEmpty(dialectClass)) { throw new PageException("When you use the PageHelper pagination plugin, you must set the helper property"); } try { Class sqlDialectClass = resloveDialectClass(dialectClass); if (AbstractHelperDialect.class.isAssignableFrom(sqlDialectClass)) { dialect = (AbstractHelperDialect) sqlDialectClass.newInstance(); } else { throw new PageException("When using PageHelper, the dialect must be an implementation class that implements the " + AbstractHelperDialect.class.getCanonicalName() + " interface!"); } } catch (Exception e) { throw new PageException("error initializing helper dialectclass[" + dialectClass + "]" + e.getMessage(), e); } dialect.setProperties(properties); return dialect; } /** * 多数据动态获取时,每次需要初始化,还可以运行时指定具体的实现 * * @param ms * @param dialectClass 分页实现,必须是 {@link AbstractHelperDialect} 实现类,可以使用当前类中注册的别名,例如 "mysql", "oracle" */ public void initDelegateDialect(MappedStatement ms, String dialectClass) { if (StringUtil.isNotEmpty(dialectClass)) { AbstractHelperDialect dialect = urlDialectMap.get(dialectClass); if (dialect == null) { lock.lock(); try { if ((dialect = urlDialectMap.get(dialectClass)) == null) { dialect = instanceDialect(dialectClass, properties); urlDialectMap.put(dialectClass, dialect); } } finally { lock.unlock(); } } dialectThreadLocal.set(dialect); } else if (delegate == null) { if (autoDialect) { this.delegate = autoGetDialect(ms); } else { dialectThreadLocal.set(autoGetDialect(ms)); } } } /** * 自动获取分页方言实现 * * @param ms * @return */ public AbstractHelperDialect autoGetDialect(MappedStatement ms) { DataSource dataSource = ms.getConfiguration().getEnvironment().getDataSource(); Object dialectKey = autoDialectDelegate.extractDialectKey(ms, dataSource, properties); if (dialectKey == null) { return autoDialectDelegate.extractDialect(dialectKey, ms, dataSource, properties); } else if (!urlDialectMap.containsKey(dialectKey)) { lock.lock(); try { if (!urlDialectMap.containsKey(dialectKey)) { urlDialectMap.put(dialectKey, autoDialectDelegate.extractDialect(dialectKey, ms, dataSource, properties)); } } finally { lock.unlock(); } } return urlDialectMap.get(dialectKey); } /** * 初始化自定义 AutoDialect * * @param properties */ private void initAutoDialectClass(Properties properties) { String autoDialectClassStr = properties.getProperty("autoDialectClass"); if (StringUtil.isNotEmpty(autoDialectClassStr)) { try { Class autoDialectClass; if (autoDialectMap.containsKey(autoDialectClassStr)) { autoDialectClass = autoDialectMap.get(autoDialectClassStr); } else { autoDialectClass = (Class) Class.forName(autoDialectClassStr); } this.autoDialectDelegate = ClassUtil.newInstance(autoDialectClass, properties); } catch (ClassNotFoundException e) { throw new IllegalArgumentException("Make sure that the AutoDialect implementation class (" + autoDialectClassStr + ") for the autoDialectClass configuration exists!", e); } catch (Exception e) { throw new RuntimeException(autoDialectClassStr + "Class must provide a constructor without parameters", e); } } else { this.autoDialectDelegate = new DataSourceNegotiationAutoDialect(); } } /** * 初始化方言别名 * * @param properties */ private void initDialectAlias(Properties properties) { String dialectAlias = properties.getProperty("dialectAlias"); if (StringUtil.isNotEmpty(dialectAlias)) { String[] alias = dialectAlias.split(";"); for (int i = 0; i < alias.length; i++) { String[] kv = alias[i].split("="); if (kv.length != 2) { throw new IllegalArgumentException("dialectAlias parameter misconfigured," + "Please follow alias1=xx.dialectClass; alias2=dialectClass2!"); } for (int j = 0; j < kv.length; j++) { try { //允许配置如 dm=oracle, 直接引用oracle实现 if (dialectAliasMap.containsKey(kv[1])) { registerDialectAlias(kv[0], dialectAliasMap.get(kv[1])); } else { Class diallectClass = (Class) Class.forName(kv[1]); //允许覆盖已有的实现 registerDialectAlias(kv[0], diallectClass); } } catch (ClassNotFoundException e) { throw new IllegalArgumentException("Make sure the Dialect implementation class configured by dialectAlias exists!", e); } } } } } public void setProperties(Properties properties) { this.properties = properties; //初始化自定义AutoDialect initAutoDialectClass(properties); //使用 sqlserver2012 作为默认分页方式,这种情况在动态数据源时方便使用 String useSqlserver2012 = properties.getProperty("useSqlserver2012"); if (StringUtil.isNotEmpty(useSqlserver2012) && Boolean.parseBoolean(useSqlserver2012)) { registerDialectAlias("sqlserver", SqlServer2012Dialect.class); registerDialectAlias("sqlserver2008", SqlServerDialect.class); } initDialectAlias(properties); //指定的 Helper 数据库方言,和 不同 String dialect = properties.getProperty("helperDialect"); //运行时获取数据源 String runtimeDialect = properties.getProperty("autoRuntimeDialect"); //1.动态多数据源 if (StringUtil.isNotEmpty(runtimeDialect) && "TRUE".equalsIgnoreCase(runtimeDialect)) { this.autoDialect = false; } //2.动态获取方言 else if (StringUtil.isEmpty(dialect)) { autoDialect = true; } //3.指定方言 else { autoDialect = false; this.delegate = instanceDialect(dialect, properties); } } } ================================================ FILE: src/main/java/com/github/pagehelper/page/PageBoundSqlInterceptors.java ================================================ /* * The MIT License (MIT) * * Copyright (c) 2014-2023 abel533@gmail.com * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ package com.github.pagehelper.page; import com.github.pagehelper.BoundSqlInterceptor; import com.github.pagehelper.BoundSqlInterceptorChain; import com.github.pagehelper.util.ClassUtil; import com.github.pagehelper.util.StringUtil; import java.util.ArrayList; import java.util.List; import java.util.Properties; public class PageBoundSqlInterceptors { private BoundSqlInterceptor.Chain chain; public void setProperties(Properties properties) { //初始化 boundSqlInterceptorChain String boundSqlInterceptorStr = properties.getProperty("boundSqlInterceptors"); if (StringUtil.isNotEmpty(boundSqlInterceptorStr)) { String[] boundSqlInterceptors = boundSqlInterceptorStr.split("[;|,]"); List list = new ArrayList(); for (int i = 0; i < boundSqlInterceptors.length; i++) { list.add(ClassUtil.newInstance(boundSqlInterceptors[i], properties)); } if (list.size() > 0) { chain = new BoundSqlInterceptorChain(null, list); } } } public BoundSqlInterceptor.Chain getChain() { return chain; } } ================================================ FILE: src/main/java/com/github/pagehelper/page/PageMethod.java ================================================ /* * The MIT License (MIT) * * Copyright (c) 2014-2023 abel533@gmail.com * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ package com.github.pagehelper.page; import com.github.pagehelper.ISelect; import com.github.pagehelper.Page; import com.github.pagehelper.util.PageObjectUtil; import java.util.Properties; /** * 基础分页方法 * * @author liuzh */ public abstract class PageMethod { protected static final ThreadLocal LOCAL_PAGE = new ThreadLocal(); protected static boolean DEFAULT_COUNT = true; /** * 设置 Page 参数 * * @param page */ public static void setLocalPage(Page page) { LOCAL_PAGE.set(page); } /** * 获取 Page 参数 * * @return */ public static Page getLocalPage() { return LOCAL_PAGE.get(); } /** * 移除本地变量 */ public static void clearPage() { LOCAL_PAGE.remove(); } /** * 获取任意查询方法的count总数 * * @param select * @return */ public static long count(ISelect select) { //单纯count查询时禁用异步count Page page = startPage(1, -1, true).disableAsyncCount(); select.doSelect(); return page.getTotal(); } /** * 开始分页 * * @param params */ public static Page startPage(Object params) { Page page = PageObjectUtil.getPageFromObject(params, true); //当已经执行过orderBy的时候 Page oldPage = getLocalPage(); if (oldPage != null && oldPage.isOrderByOnly()) { page.setOrderBy(oldPage.getOrderBy()); } setLocalPage(page); return page; } /** * 开始分页 * * @param pageNum 页码 * @param pageSize 每页显示数量 */ public static Page startPage(int pageNum, int pageSize) { return startPage(pageNum, pageSize, DEFAULT_COUNT); } /** * 开始分页 * * @param pageNum 页码 * @param pageSize 每页显示数量 * @param count 是否进行count查询 */ public static Page startPage(int pageNum, int pageSize, boolean count) { return startPage(pageNum, pageSize, count, null, null); } /** * 开始分页 * * @param pageNum 页码 * @param pageSize 每页显示数量 * @param orderBy 排序 */ public static Page startPage(int pageNum, int pageSize, String orderBy) { Page page = startPage(pageNum, pageSize); page.setOrderBy(orderBy); return page; } /** * 开始分页 * * @param pageNum 页码 * @param pageSize 每页显示数量 * @param count 是否进行count查询 * @param reasonable 分页合理化,null时用默认配置 * @param pageSizeZero true且pageSize=0时返回全部结果,false时分页,null时用默认配置 */ public static Page startPage(int pageNum, int pageSize, boolean count, Boolean reasonable, Boolean pageSizeZero) { Page page = new Page(pageNum, pageSize, count); page.setReasonable(reasonable); page.setPageSizeZero(pageSizeZero); //当已经执行过orderBy的时候 Page oldPage = getLocalPage(); if (oldPage != null && oldPage.isOrderByOnly()) { page.setOrderBy(oldPage.getOrderBy()); } setLocalPage(page); return page; } /** * 开始分页 * * @param offset 起始位置,偏移位置 * @param limit 每页显示数量 */ public static Page offsetPage(int offset, int limit) { return offsetPage(offset, limit, DEFAULT_COUNT); } /** * 开始分页 * * @param offset 起始位置,偏移位置 * @param limit 每页显示数量 * @param count 是否进行count查询 */ public static Page offsetPage(int offset, int limit, boolean count) { Page page = new Page(new int[]{offset, limit}, count); //当已经执行过orderBy的时候 Page oldPage = getLocalPage(); if (oldPage != null && oldPage.isOrderByOnly()) { page.setOrderBy(oldPage.getOrderBy()); } setLocalPage(page); return page; } /** * 排序 * * @param orderBy */ public static void orderBy(String orderBy) { Page page = getLocalPage(); if (page != null) { page.setOrderBy(orderBy); if (page.getPageSizeZero() != null && page.getPageSizeZero() && page.getPageSize() == 0) { page.setOrderByOnly(true); } } else { page = new Page(); page.setOrderBy(orderBy); page.setOrderByOnly(true); setLocalPage(page); } } /** * 设置参数 * * @param properties 插件属性 */ protected static void setStaticProperties(Properties properties) { //defaultCount,这是一个全局生效的参数,多数据源时也是统一的行为 if (properties != null) { DEFAULT_COUNT = Boolean.valueOf(properties.getProperty("defaultCount", "true")); } } } ================================================ FILE: src/main/java/com/github/pagehelper/page/PageParams.java ================================================ /* * The MIT License (MIT) * * Copyright (c) 2014-2023 abel533@gmail.com * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ package com.github.pagehelper.page; import com.github.pagehelper.IPage; import com.github.pagehelper.Page; import com.github.pagehelper.PageHelper; import com.github.pagehelper.PageRowBounds; import com.github.pagehelper.util.PageObjectUtil; import com.github.pagehelper.util.StringUtil; import org.apache.ibatis.session.RowBounds; import java.util.Properties; /** * Page 参数信息 * * @author liuzh */ public class PageParams { /** * RowBounds参数offset作为PageNum使用 - 默认不使用 */ protected boolean offsetAsPageNum = false; /** * RowBounds是否进行count查询 - 默认不查询 */ protected boolean rowBoundsWithCount = false; /** * 当设置为true的时候,如果pagesize设置为0(或RowBounds的limit=0),就不执行分页,返回全部结果 */ protected boolean pageSizeZero = false; /** * 分页合理化 */ protected boolean reasonable = false; /** * 是否支持接口参数来传递分页参数,默认false */ protected boolean supportMethodsArguments = false; /** * 默认count(0) */ protected String countColumn = "0"; /** * 转换count查询时保留 order by 排序 */ private boolean keepOrderBy = false; /** * 转换count查询时保留子查询的 order by 排序 */ private boolean keepSubSelectOrderBy = false; /** * 异步count查询 */ private boolean asyncCount = false; /** * 获取分页参数 * * @param parameterObject * @param rowBounds * @return */ public Page getPage(Object parameterObject, RowBounds rowBounds) { Page page = PageHelper.getLocalPage(); if (page == null) { if (rowBounds != RowBounds.DEFAULT) { if (offsetAsPageNum) { page = new Page(rowBounds.getOffset(), rowBounds.getLimit(), rowBoundsWithCount); } else { page = new Page(new int[]{rowBounds.getOffset(), rowBounds.getLimit()}, rowBoundsWithCount); //offsetAsPageNum=false的时候,由于PageNum问题,不能使用reasonable,这里会强制为false page.setReasonable(false); } if (rowBounds instanceof PageRowBounds) { PageRowBounds pageRowBounds = (PageRowBounds) rowBounds; page.setCount(pageRowBounds.getCount() == null || pageRowBounds.getCount()); } } else if (parameterObject instanceof IPage || supportMethodsArguments) { try { page = PageObjectUtil.getPageFromObject(parameterObject, false); } catch (Exception e) { return null; } } if (page == null) { return null; } PageHelper.setLocalPage(page); } //分页合理化 if (page.getReasonable() == null) { page.setReasonable(reasonable); } //当设置为true的时候,如果pagesize设置为0(或RowBounds的limit=0),就不执行分页,返回全部结果 if (page.getPageSizeZero() == null) { page.setPageSizeZero(pageSizeZero); } if (page.getKeepOrderBy() == null) { page.setKeepOrderBy(keepOrderBy); } if (page.getKeepSubSelectOrderBy() == null) { page.setKeepSubSelectOrderBy(keepSubSelectOrderBy); } return page; } public void setProperties(Properties properties) { //offset作为PageNum使用 String offsetAsPageNum = properties.getProperty("offsetAsPageNum"); this.offsetAsPageNum = Boolean.parseBoolean(offsetAsPageNum); //RowBounds方式是否做count查询 String rowBoundsWithCount = properties.getProperty("rowBoundsWithCount"); this.rowBoundsWithCount = Boolean.parseBoolean(rowBoundsWithCount); //当设置为true的时候,如果pagesize设置为0(或RowBounds的limit=0),就不执行分页 String pageSizeZero = properties.getProperty("pageSizeZero"); this.pageSizeZero = Boolean.parseBoolean(pageSizeZero); //分页合理化,true开启,如果分页参数不合理会自动修正。默认false不启用 String reasonable = properties.getProperty("reasonable"); this.reasonable = Boolean.parseBoolean(reasonable); //是否支持接口参数来传递分页参数,默认false String supportMethodsArguments = properties.getProperty("supportMethodsArguments"); this.supportMethodsArguments = Boolean.parseBoolean(supportMethodsArguments); //默认count列 String countColumn = properties.getProperty("countColumn"); if (StringUtil.isNotEmpty(countColumn)) { this.countColumn = countColumn; } //当offsetAsPageNum=false的时候,不能 //参数映射 PageObjectUtil.setParams(properties.getProperty("params")); // count查询时,是否保留查询中的 order by keepOrderBy = Boolean.parseBoolean(properties.getProperty("keepOrderBy")); // count查询时,是否保留子查询中的 order by keepSubSelectOrderBy = Boolean.parseBoolean(properties.getProperty("keepSubSelectOrderBy")); // 异步count查询 asyncCount = Boolean.parseBoolean(properties.getProperty("asyncCount")); } public boolean isOffsetAsPageNum() { return offsetAsPageNum; } public boolean isRowBoundsWithCount() { return rowBoundsWithCount; } public boolean isPageSizeZero() { return pageSizeZero; } public boolean isReasonable() { return reasonable; } public boolean isSupportMethodsArguments() { return supportMethodsArguments; } public String getCountColumn() { return countColumn; } public boolean isAsyncCount() { return asyncCount; } } ================================================ FILE: src/main/java/com/github/pagehelper/parser/CountSqlParser.java ================================================ /* * The MIT License (MIT) * * Copyright (c) 2014-2023 abel533@gmail.com * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ package com.github.pagehelper.parser; import com.github.pagehelper.util.StringUtil; import java.util.Arrays; import java.util.HashSet; import java.util.Set; public interface CountSqlParser { /** * 聚合函数,以下列函数开头的都认为是聚合函数 */ Set AGGREGATE_FUNCTIONS = new HashSet(Arrays.asList( ("APPROX_COUNT_DISTINCT," + "ARRAY_AGG," + "AVG," + "BIT_," + //"BIT_AND," + //"BIT_OR," + //"BIT_XOR," + "BOOL_," + //"BOOL_AND," + //"BOOL_OR," + "CHECKSUM_AGG," + "COLLECT," + "CORR," + //"CORR_," + //"CORRELATION," + "COUNT," + //"COUNT_BIG," + "COVAR," + //"COVAR_POP," + //"COVAR_SAMP," + //"COVARIANCE," + //"COVARIANCE_SAMP," + "CUME_DIST," + "DENSE_RANK," + "EVERY," + "FIRST," + "GROUP," + //"GROUP_CONCAT," + //"GROUP_ID," + //"GROUPING," + //"GROUPING," + //"GROUPING_ID," + "JSON_," + //"JSON_AGG," + //"JSON_ARRAYAGG," + //"JSON_OBJECT_AGG," + //"JSON_OBJECTAGG," + //"JSONB_AGG," + //"JSONB_OBJECT_AGG," + "LAST," + "LISTAGG," + "MAX," + "MEDIAN," + "MIN," + "PERCENT_," + //"PERCENT_RANK," + //"PERCENTILE_CONT," + //"PERCENTILE_DISC," + "RANK," + "REGR_," + "SELECTIVITY," + "STATS_," + //"STATS_BINOMIAL_TEST," + //"STATS_CROSSTAB," + //"STATS_F_TEST," + //"STATS_KS_TEST," + //"STATS_MODE," + //"STATS_MW_TEST," + //"STATS_ONE_WAY_ANOVA," + //"STATS_T_TEST_*," + //"STATS_WSR_TEST," + "STD," + //"STDDEV," + //"STDDEV_POP," + //"STDDEV_SAMP," + //"STDDEV_SAMP," + //"STDEV," + //"STDEVP," + "STRING_AGG," + "SUM," + "SYS_OP_ZONE_ID," + "SYS_XMLAGG," + "VAR," + //"VAR_POP," + //"VAR_SAMP," + //"VARIANCE," + //"VARIANCE_SAMP," + //"VARP," + "XMLAGG").split(","))); /** * 添加到聚合函数,可以是逗号隔开的多个函数前缀 * * @param functions */ static void addAggregateFunctions(String functions) { if (StringUtil.isNotEmpty(functions)) { String[] funs = functions.split(","); for (int i = 0; i < funs.length; i++) { AGGREGATE_FUNCTIONS.add(funs[i].toUpperCase()); } } } /** * 获取智能的countSql * * @param sql */ default String getSmartCountSql(String sql) { return getSmartCountSql(sql, "0"); } /** * 获取智能的countSql * * @param sql * @param countColumn 列名,默认 0 */ String getSmartCountSql(String sql, String countColumn); } ================================================ FILE: src/main/java/com/github/pagehelper/parser/OrderBySqlParser.java ================================================ /* * The MIT License (MIT) * * Copyright (c) 2014-2023 abel533@gmail.com * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ package com.github.pagehelper.parser; public interface OrderBySqlParser { String converToOrderBySql(String sql, String orderBy); } ================================================ FILE: src/main/java/com/github/pagehelper/parser/SqlParser.java ================================================ /* * The MIT License (MIT) * * Copyright (c) 2014-2023 abel533@gmail.com * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ package com.github.pagehelper.parser; import net.sf.jsqlparser.JSQLParserException; import net.sf.jsqlparser.parser.CCJSqlParser; import net.sf.jsqlparser.parser.CCJSqlParserUtil; import net.sf.jsqlparser.parser.ParseException; import net.sf.jsqlparser.statement.Statement; /** * 为了能自己控制是否使用单线程池,是否支持超时控制,所以自己实现了一个 * * @author liuzh */ public interface SqlParser { /** * 不使用单线程池,不支持超时控制 */ SqlParser DEFAULT = statementReader -> { CCJSqlParser parser = CCJSqlParserUtil.newParser(statementReader); parser.withSquareBracketQuotation(true); return parser.Statement(); }; /** * 解析 SQL * * @param statementReader SQL * @return * @throws JSQLParserException */ Statement parse(String statementReader) throws JSQLParserException, ParseException; } ================================================ FILE: src/main/java/com/github/pagehelper/parser/SqlParserUtil.java ================================================ package com.github.pagehelper.parser; import net.sf.jsqlparser.JSQLParserException; import net.sf.jsqlparser.parser.ParseException; import net.sf.jsqlparser.statement.Statement; import java.util.ServiceLoader; public class SqlParserUtil { private static final SqlParser SQL_PARSER; static { SqlParser temp = null; ServiceLoader loader = ServiceLoader.load(SqlParser.class); for (SqlParser sqlParser : loader) { temp = sqlParser; break; } if (temp == null) { temp = SqlParser.DEFAULT; } SQL_PARSER = temp; } public static Statement parse(String statementReader) { try { return SQL_PARSER.parse(statementReader); } catch (JSQLParserException | ParseException e) { throw new RuntimeException(e); } } } ================================================ FILE: src/main/java/com/github/pagehelper/parser/SqlServerSqlParser.java ================================================ /* * The MIT License (MIT) * * Copyright (c) 2014-2023 abel533@gmail.com * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ package com.github.pagehelper.parser; /** * 针对 sqlserver 的分页解析 */ public interface SqlServerSqlParser { String convertToPageSql(String sql, Integer offset, Integer limit); } ================================================ FILE: src/main/java/com/github/pagehelper/parser/defaults/DefaultCountSqlParser.java ================================================ /* * The MIT License (MIT) * * Copyright (c) 2014-2023 abel533@gmail.com * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ package com.github.pagehelper.parser.defaults; import com.github.pagehelper.page.PageMethod; import com.github.pagehelper.parser.CountSqlParser; import com.github.pagehelper.parser.SqlParserUtil; import net.sf.jsqlparser.expression.Alias; import net.sf.jsqlparser.expression.Expression; import net.sf.jsqlparser.expression.Function; import net.sf.jsqlparser.expression.Parenthesis; import net.sf.jsqlparser.parser.Token; import net.sf.jsqlparser.schema.Column; import net.sf.jsqlparser.statement.Statement; import net.sf.jsqlparser.statement.select.*; import java.util.*; /** * sql解析类,提供更智能的count查询sql * * @author liuzh */ public class DefaultCountSqlParser implements CountSqlParser { public static final String KEEP_ORDERBY = "/*keep orderby*/"; protected static final Alias TABLE_ALIAS; protected final Set skipFunctions = Collections.synchronizedSet(new HashSet<>()); protected final Set falseFunctions = Collections.synchronizedSet(new HashSet<>()); static { TABLE_ALIAS = new Alias("table_count"); TABLE_ALIAS.setUseAs(false); } /** * 获取智能的countSql * * @param sql * @param countColumn 列名,默认 0 * @return */ @Override public String getSmartCountSql(String sql, String countColumn) { // 解析SQL Statement stmt = null; // 特殊sql不需要去掉order by时,使用注释前缀 if (sql.indexOf(KEEP_ORDERBY) >= 0 || keepOrderBy()) { return getSimpleCountSql(sql, countColumn); } try { stmt = SqlParserUtil.parse(sql); } catch (Throwable e) { // 无法解析的用一般方法返回count语句 return getSimpleCountSql(sql, countColumn); } Select select = (Select) stmt; try { // 处理body-去order by processSelect(select); } catch (Exception e) { // 当 sql 包含 group by 时,不去除 order by return getSimpleCountSql(sql, countColumn); } // 处理with-去order by processWithItemsList(select.getWithItemsList()); // 处理为count查询 Select countSelect = sqlToCount(select, countColumn); String result = countSelect.toString(); if (select instanceof PlainSelect) { Token token = select.getASTNode().jjtGetFirstToken().specialToken; if (token != null) { String hints = token.toString().trim(); // 这里判断是否存在hint, 且result是不包含hint的 if (hints.startsWith("/*") && hints.endsWith("*/") && !result.startsWith("/*")) { result = hints + result; } } } return result; } /** * 获取普通的Count-sql * * @param sql 原查询sql * @return 返回count查询sql */ public String getSimpleCountSql(final String sql) { return getSimpleCountSql(sql, "0"); } /** * 获取普通的Count-sql * * @param sql 原查询sql * @return 返回count查询sql */ public String getSimpleCountSql(final String sql, String name) { StringBuilder stringBuilder = new StringBuilder(sql.length() + 40); stringBuilder.append("select count("); stringBuilder.append(name); stringBuilder.append(") from ( \n"); stringBuilder.append(sql); stringBuilder.append("\n ) tmp_count"); return stringBuilder.toString(); } /** * 将sql转换为count查询 * * @param select */ public Select sqlToCount(Select select, String name) { // 是否能简化count查询 List> COUNT_ITEM = new ArrayList<>(); COUNT_ITEM.add(new SelectItem(new Column("count(" + name + ")"))); if (select instanceof PlainSelect && isSimpleCount((PlainSelect) select)) { ((PlainSelect) select).setSelectItems(COUNT_ITEM); return select; } else { PlainSelect plainSelect = new PlainSelect(); ParenthesedSelect subSelect = new ParenthesedSelect(); subSelect.setSelect(select); subSelect.setAlias(TABLE_ALIAS); plainSelect.setFromItem(subSelect); plainSelect.setSelectItems(COUNT_ITEM); if (select.getWithItemsList() != null) { plainSelect.setWithItemsList(select.getWithItemsList()); select.setWithItemsList(null); } return plainSelect; } } /** * 是否可以用简单的count查询方式 * * @param select * @return */ public boolean isSimpleCount(PlainSelect select) { // #868 Cannot use simple count when ORDER BY contains parameters // If ORDER BY contains parameters, removing it will cause JDBC parameter // mismatch // Fixed by @pwdLight - // https://github.com/pagehelper/Mybatis-PageHelper/pull/869 if (orderByHashParameters(select.getOrderByElements())) { return false; } // 包含group by的时候不可以 if (select.getGroupBy() != null) { return false; } // 包含distinct的时候不可以 if (select.getDistinct() != null) { return false; } // #606,包含having时不可以 if (select.getHaving() != null) { return false; } for (SelectItem item : select.getSelectItems()) { // select列中包含参数的时候不可以,否则会引起参数个数错误 if (item.toString().contains("?")) { return false; } // 如果查询列中包含函数,也不可以,函数可能会聚合列 Expression expression = item.getExpression(); if (expression instanceof Function) { String name = ((Function) expression).getName(); if (name != null) { String NAME = name.toUpperCase(); if (skipFunctions.contains(NAME)) { // go on } else if (falseFunctions.contains(NAME)) { return false; } else { for (String aggregateFunction : AGGREGATE_FUNCTIONS) { if (NAME.startsWith(aggregateFunction)) { falseFunctions.add(NAME); return false; } } skipFunctions.add(NAME); } } } else if (expression instanceof Parenthesis && item.getAlias() != null) { // #555,当存在 (a+b) as c 时,c 如果出现了 order by 或者 having 中时,会找不到对应的列, // 这里想要更智能,需要在整个SQL中查找别名出现的位置,暂时不考虑,直接排除 return false; } } return true; } /** * 处理selectBody去除Order by * * @param select */ public void processSelect(Select select) { if (select != null) { if (select instanceof PlainSelect) { processPlainSelect((PlainSelect) select); } else if (select instanceof ParenthesedSelect) { processSelect(((ParenthesedSelect) select).getSelect()); } else if (select instanceof SetOperationList) { List plainSelects = operationList.getSelects(); for (Select plainSelect : plainSelects) { processSelectBody(plainSelect, level + 1); } } } } } /** * 处理PlainSelect类型的selectBody * * @param plainSelect */ protected void processPlainSelect(PlainSelect plainSelect, int level) { if (level > 1) { if (isNotEmptyList(plainSelect.getOrderByElements())) { if (plainSelect.getTop() == null) { plainSelect.setTop(TOP100_PERCENT); } } } if (plainSelect.getFromItem() != null) { processFromItem(plainSelect.getFromItem(), level + 1); } if (plainSelect.getJoins() != null && !plainSelect.getJoins().isEmpty()) { List joins = plainSelect.getJoins(); for (Join join : joins) { if (join.getRightItem() != null) { processFromItem(join.getRightItem(), level + 1); } } } } /** * 处理子查询 * * @param fromItem */ protected void processFromItem(FromItem fromItem, int level) { if (fromItem instanceof LateralSubSelect) { processSelectBody(((LateralSubSelect) fromItem).getSelect(), level + 1); } else if (fromItem instanceof ParenthesedSelect) { processSelectBody(((ParenthesedSelect) fromItem).getSelect(), level + 1); } else if (fromItem instanceof Select) { processSelectBody((Select) fromItem, level + 1); } else if (fromItem instanceof ParenthesedFromItem) { processFromItem(((ParenthesedFromItem) fromItem).getFromItem(), level + 1); } //Table时不用处理 } /** * List不空 * * @param list * @return */ public boolean isNotEmptyList(List list) { if (list == null || list.isEmpty()) { return false; } return true; } /** * 复制 OrderByElement * * @param orig 原 OrderByElement * @param alias 新 OrderByElement 的排序要素 * @return 复制的新 OrderByElement */ protected OrderByElement cloneOrderByElement(OrderByElement orig, String alias) { return cloneOrderByElement(orig, new Column(alias)); } /** * 复制 OrderByElement * * @param orig 原 OrderByElement * @param expression 新 OrderByElement 的排序要素 * @return 复制的新 OrderByElement */ protected OrderByElement cloneOrderByElement(OrderByElement orig, Expression expression) { OrderByElement element = new OrderByElement(); element.setAsc(orig.isAsc()); element.setAscDescPresent(orig.isAscDescPresent()); element.setNullOrdering(orig.getNullOrdering()); element.setExpression(expression); return element; } /** * 获取新的排序列表 * * @param plainSelect 原始查询 * @param autoItems 生成的新查询要素 * @return 新的排序列表 */ protected List getOrderByElements(PlainSelect plainSelect, List> autoItems) { List orderByElements = plainSelect.getOrderByElements(); ListIterator iterator = orderByElements.listIterator(); OrderByElement orderByElement; // 非 `*` 且 非 `t.*` 查询列集合 Map> selectMap = new HashMap<>(); // 别名集合 Set aliases = new HashSet(); // 是否包含 `*` 查询列 boolean allColumns = false; // `t.*` 查询列的表名集合 Set allColumnsTables = new HashSet(); for (SelectItem item : plainSelect.getSelectItems()) { Expression expression = item.getExpression(); if (expression instanceof AllTableColumns) { allColumnsTables.add(((AllTableColumns) expression).getTable().getName()); } else if (expression instanceof AllColumns) { allColumns = true; } else { selectMap.put(expression.toString(), item); Alias alias = item.getAlias(); if (alias != null) { aliases.add(alias.getName()); } } } // 开始遍历 OrderByElement 列表 int aliasNo = 1; while (iterator.hasNext()) { orderByElement = iterator.next(); Expression expression = orderByElement.getExpression(); SelectItem selectExpressionItem = selectMap.get(expression.toString()); if (selectExpressionItem != null) { // OrderByElement 在查询列表中 Alias alias = selectExpressionItem.getAlias(); if (alias != null) { // 查询列含有别名时用查询列别名 iterator.set(cloneOrderByElement(orderByElement, alias.getName())); } else { // 查询列不包含别名 if (expression instanceof Column) { // 查询列为普通列,这时因为列在嵌套查询外时名称中不包含表名,故去除排序列的表名引用 // 例(仅为解释此处逻辑,不代表最终分页结果): // SELECT TEST.A FROM TEST ORDER BY TEST.A // --> // SELECT A FROM (SELECT TEST.A FROM TEST) ORDER BY A ((Column) expression).setTable(null); } else { // 查询列不为普通列时(例如函数列)不支持分页 // 此种情况比较难预测,简单的增加新列容易产生不可预料的结果 // 而为列增加别名是非常简单的,故此要求排序复杂列必须使用别名 throw new PageException("The column \"" + expression + "\" needs to define an alias"); } } } else { // OrderByElement 不在查询列表中,需要自动生成一个查询列 if (expression instanceof Column) { // OrderByElement 为普通列 Table table = ((Column) expression).getTable(); if (table == null) { // 表名为空 if (allColumns || (allColumnsTables.size() == 1 && plainSelect.getJoins() == null) || aliases.contains(((Column) expression).getColumnName())) { // 包含`*`查询列 或者 只有一个 `t.*`列且为单表查询 或者 其实排序列是一个别名 // 此时排序列其实已经包含在查询列表中了,不需做任何操作 continue; } } else { //表名不为空 String tableName = table.getName(); if (allColumns || allColumnsTables.contains(tableName)) { // 包含`*`查询列 或者 包含特定的`t.*`列 // 此时排序列其实已经包含在查询列表中了,只需去除排序列的表名引 ((Column) expression).setTable(null); continue; } } } // 将排序列加入查询列中 String aliasName = PAGE_COLUMN_ALIAS_PREFIX + aliasNo++; SelectItem item = new SelectItem<>(expression); item.setAlias(new Alias(aliasName)); autoItems.add(item); iterator.set(cloneOrderByElement(orderByElement, aliasName)); } } return orderByElements; } } ================================================ FILE: src/main/java/com/github/pagehelper/util/ClassUtil.java ================================================ /* * The MIT License (MIT) * * Copyright (c) 2014-2023 abel533@gmail.com * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ package com.github.pagehelper.util; import com.github.pagehelper.PageException; import com.github.pagehelper.PageProperties; import java.util.Properties; import java.util.ServiceLoader; import java.util.function.Supplier; public class ClassUtil { /** * 支持配置和SPI,优先级:配置类 > SPI > 默认值 * * @param classStr 配置串,可空 * @param spi SPI 接口 * @param properties 配置属性 * @param defaultSupplier 默认值 */ @SuppressWarnings("unchecked") public static T newInstance(String classStr, Class spi, Properties properties, Supplier defaultSupplier) { if (StringUtil.isNotEmpty(classStr)) { try { Class cls = Class.forName(classStr); return (T) newInstance(cls, properties); } catch (Exception ignored) { } } T result = null; if (spi != null) { ServiceLoader loader = ServiceLoader.load(spi); for (T t : loader) { result = t; break; } } if (result == null) { result = defaultSupplier.get(); } if (result instanceof PageProperties) { ((PageProperties) result).setProperties(properties); } return result; } @SuppressWarnings("unchecked") public static T newInstance(String classStr, Properties properties) { try { Class cls = Class.forName(classStr); return (T) newInstance(cls, properties); } catch (Exception e) { throw new PageException(e); } } public static T newInstance(Class cls, Properties properties) { try { T instance = cls.newInstance(); if (instance instanceof PageProperties) { ((PageProperties) instance).setProperties(properties); } return instance; } catch (Exception e) { throw new PageException(e); } } public static Class getServletRequestClass() throws ClassNotFoundException { Class requestClass = null; try { requestClass = Class.forName("javax.servlet.ServletRequest"); }catch (ClassNotFoundException exception){ } if (requestClass != null){ return requestClass; } return Class.forName("jakarta.servlet.ServletRequest"); } } ================================================ FILE: src/main/java/com/github/pagehelper/util/ExecutorUtil.java ================================================ /* * The MIT License (MIT) * * Copyright (c) 2014-2023 abel533@gmail.com * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ package com.github.pagehelper.util; import com.github.pagehelper.BoundSqlInterceptor; import com.github.pagehelper.Dialect; import com.github.pagehelper.PageException; import org.apache.ibatis.builder.annotation.ProviderSqlSource; import org.apache.ibatis.cache.CacheKey; import org.apache.ibatis.executor.Executor; import org.apache.ibatis.mapping.BoundSql; import org.apache.ibatis.mapping.MappedStatement; import org.apache.ibatis.session.Configuration; import org.apache.ibatis.session.ResultHandler; import org.apache.ibatis.session.RowBounds; import java.lang.reflect.Field; import java.sql.SQLException; import java.util.List; import java.util.Map; /** * @author liuzenghui */ public abstract class ExecutorUtil { private static Field additionalParametersField; private static Field providerMethodArgumentNamesField; static { try { additionalParametersField = BoundSql.class.getDeclaredField("additionalParameters"); additionalParametersField.setAccessible(true); } catch (NoSuchFieldException e) { throw new PageException("Failed to get the BoundSql property additionalParameters: " + e, e); } try { //兼容低版本 providerMethodArgumentNamesField = ProviderSqlSource.class.getDeclaredField("providerMethodArgumentNames"); providerMethodArgumentNamesField.setAccessible(true); } catch (NoSuchFieldException ignore) { } } /** * 获取 BoundSql 属性值 additionalParameters * * @param boundSql * @return */ public static Map getAdditionalParameter(BoundSql boundSql) { try { return (Map) additionalParametersField.get(boundSql); } catch (IllegalAccessException e) { throw new PageException("Failed to get the BoundSql property additionalParameters: " + e, e); } } /** * 获取 ProviderSqlSource 属性值 providerMethodArgumentNames * * @param providerSqlSource * @return */ public static String[] getProviderMethodArgumentNames(ProviderSqlSource providerSqlSource) { try { return providerMethodArgumentNamesField != null ? (String[]) providerMethodArgumentNamesField.get(providerSqlSource) : null; } catch (IllegalAccessException e) { throw new PageException("Get the ProviderSqlSource property value of providerMethodArgumentNames: " + e, e); } } /** * 尝试获取已经存在的在 MS,提供对手写count和page的支持 * * @param configuration * @param msId * @return */ public static MappedStatement getExistedMappedStatement(Configuration configuration, String msId) { MappedStatement mappedStatement = null; try { mappedStatement = configuration.getMappedStatement(msId, false); } catch (Throwable t) { //ignore } return mappedStatement; } /** * 执行手动设置的 count 查询,该查询支持的参数必须和被分页的方法相同 * * @param executor * @param countMs * @param parameter * @param boundSql * @param resultHandler * @return * @throws SQLException */ public static Long executeManualCount(Executor executor, MappedStatement countMs, Object parameter, BoundSql boundSql, ResultHandler resultHandler) throws SQLException { CacheKey countKey = executor.createCacheKey(countMs, parameter, RowBounds.DEFAULT, boundSql); BoundSql countBoundSql = countMs.getBoundSql(parameter); Object countResultList = executor.query(countMs, parameter, RowBounds.DEFAULT, resultHandler, countKey, countBoundSql); //某些数据(如 TDEngine)查询 count 无结果时返回 null if (countResultList == null || ((List) countResultList).isEmpty()) { return 0L; } return ((Number) ((List) countResultList).get(0)).longValue(); } /** * 执行自动生成的 count 查询 * * @param dialect * @param executor * @param countMs * @param parameter * @param boundSql * @param rowBounds * @param resultHandler * @return * @throws SQLException */ public static Long executeAutoCount(Dialect dialect, Executor executor, MappedStatement countMs, Object parameter, BoundSql boundSql, RowBounds rowBounds, ResultHandler resultHandler) throws SQLException { Map additionalParameters = getAdditionalParameter(boundSql); //创建 count 查询的缓存 key CacheKey countKey = executor.createCacheKey(countMs, parameter, RowBounds.DEFAULT, boundSql); //调用方言获取 count sql String countSql = dialect.getCountSql(countMs, boundSql, parameter, rowBounds, countKey); //countKey.update(countSql); BoundSql countBoundSql = new BoundSql(countMs.getConfiguration(), countSql, boundSql.getParameterMappings(), parameter); //当使用动态 SQL 时,可能会产生临时的参数,这些参数需要手动设置到新的 BoundSql 中 for (String key : additionalParameters.keySet()) { countBoundSql.setAdditionalParameter(key, additionalParameters.get(key)); } //对 boundSql 的拦截处理 if (dialect instanceof BoundSqlInterceptor.Chain) { countBoundSql = ((BoundSqlInterceptor.Chain) dialect).doBoundSql(BoundSqlInterceptor.Type.COUNT_SQL, countBoundSql, countKey); } //执行 count 查询 Object countResultList = executor.query(countMs, parameter, RowBounds.DEFAULT, resultHandler, countKey, countBoundSql); //某些数据(如 TDEngine)查询 count 无结果时返回 null if (countResultList == null || ((List) countResultList).isEmpty()) { return 0L; } return ((Number) ((List) countResultList).get(0)).longValue(); } /** * 分页查询 * * @param dialect * @param executor * @param ms * @param parameter * @param rowBounds * @param resultHandler * @param boundSql * @param cacheKey * @param * @return * @throws SQLException */ public static List pageQuery(Dialect dialect, Executor executor, MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql, CacheKey cacheKey) throws SQLException { //判断是否需要进行分页查询 if (dialect.beforePage(ms, parameter, rowBounds)) { //生成分页的缓存 key CacheKey pageKey = cacheKey; //处理参数对象 parameter = dialect.processParameterObject(ms, parameter, boundSql, pageKey); //调用方言获取分页 sql String pageSql = dialect.getPageSql(ms, boundSql, parameter, rowBounds, pageKey); BoundSql pageBoundSql = new BoundSql(ms.getConfiguration(), pageSql, boundSql.getParameterMappings(), parameter); Map additionalParameters = getAdditionalParameter(boundSql); //设置动态参数 for (String key : additionalParameters.keySet()) { pageBoundSql.setAdditionalParameter(key, additionalParameters.get(key)); } //对 boundSql 的拦截处理 if (dialect instanceof BoundSqlInterceptor.Chain) { pageBoundSql = ((BoundSqlInterceptor.Chain) dialect).doBoundSql(BoundSqlInterceptor.Type.PAGE_SQL, pageBoundSql, pageKey); } //执行分页查询 return executor.query(ms, parameter, RowBounds.DEFAULT, resultHandler, pageKey, pageBoundSql); } else { //不执行分页的情况下,也不执行内存分页 return executor.query(ms, parameter, RowBounds.DEFAULT, resultHandler, cacheKey, boundSql); } } } ================================================ FILE: src/main/java/com/github/pagehelper/util/MSUtils.java ================================================ /* * The MIT License (MIT) * * Copyright (c) 2014-2023 abel533@gmail.com * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ package com.github.pagehelper.util; import org.apache.ibatis.mapping.MappedStatement; import org.apache.ibatis.mapping.ResultMap; import org.apache.ibatis.mapping.ResultMapping; import java.util.ArrayList; import java.util.List; /** * 创建新的MappedStatement,主要是Count返回值int * * @author liuzh */ public class MSUtils { private static final List EMPTY_RESULTMAPPING = new ArrayList(0); /** * 新建count查询的MappedStatement * * @param ms * @param newMsId * @return */ public static MappedStatement newCountMappedStatement(MappedStatement ms, String newMsId) { MappedStatement.Builder builder = new MappedStatement.Builder(ms.getConfiguration(), newMsId, ms.getSqlSource(), ms.getSqlCommandType()); builder.resource(ms.getResource()); builder.fetchSize(ms.getFetchSize()); builder.statementType(ms.getStatementType()); builder.keyGenerator(ms.getKeyGenerator()); if (ms.getKeyProperties() != null && ms.getKeyProperties().length != 0) { StringBuilder keyProperties = new StringBuilder(); for (String keyProperty : ms.getKeyProperties()) { keyProperties.append(keyProperty).append(","); } keyProperties.delete(keyProperties.length() - 1, keyProperties.length()); builder.keyProperty(keyProperties.toString()); } builder.timeout(ms.getTimeout()); builder.parameterMap(ms.getParameterMap()); //count查询返回值int List resultMaps = new ArrayList(); ResultMap resultMap = new ResultMap.Builder(ms.getConfiguration(), ms.getId(), Long.class, EMPTY_RESULTMAPPING).build(); resultMaps.add(resultMap); builder.resultMaps(resultMaps); builder.resultSetType(ms.getResultSetType()); builder.cache(ms.getCache()); builder.flushCacheRequired(ms.isFlushCacheRequired()); builder.useCache(ms.isUseCache()); return builder.build(); } } ================================================ FILE: src/main/java/com/github/pagehelper/util/MetaObjectUtil.java ================================================ /* * The MIT License (MIT) * * Copyright (c) 2014-2023 abel533@gmail.com * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ package com.github.pagehelper.util; import com.github.pagehelper.PageException; import org.apache.ibatis.reflection.MetaObject; import java.lang.reflect.Method; /** * @author liuzh */ public class MetaObjectUtil { public static Method method; static { try { // 高版本中的 MetaObject.forObject 有 4 个参数,低版本是 1 个 //先判断当前使用的是否为高版本 Class.forName("org.apache.ibatis.reflection.ReflectorFactory"); // 下面这个 MetaObjectWithReflectCache 带反射的缓存信息 Class metaClass = Class.forName("com.github.pagehelper.util.MetaObjectWithReflectCache"); method = metaClass.getDeclaredMethod("forObject", Object.class); } catch (Throwable e1) { try { Class metaClass = Class.forName("org.apache.ibatis.reflection.SystemMetaObject"); method = metaClass.getDeclaredMethod("forObject", Object.class); } catch (Exception e2) { try { Class metaClass = Class.forName("org.apache.ibatis.reflection.MetaObject"); method = metaClass.getDeclaredMethod("forObject", Object.class); } catch (Exception e3) { throw new PageException(e3); } } } } public static MetaObject forObject(Object object) { try { return (MetaObject) method.invoke(null, object); } catch (Exception e) { throw new PageException(e); } } } ================================================ FILE: src/main/java/com/github/pagehelper/util/MetaObjectWithReflectCache.java ================================================ /* * The MIT License (MIT) * * Copyright (c) 2014-2023 abel533@gmail.com * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ package com.github.pagehelper.util; import com.github.pagehelper.PageException; import org.apache.ibatis.reflection.DefaultReflectorFactory; import org.apache.ibatis.reflection.MetaObject; import org.apache.ibatis.reflection.ReflectorFactory; import org.apache.ibatis.reflection.factory.DefaultObjectFactory; import org.apache.ibatis.reflection.factory.ObjectFactory; import org.apache.ibatis.reflection.wrapper.DefaultObjectWrapperFactory; import org.apache.ibatis.reflection.wrapper.ObjectWrapperFactory; /** * 反射带缓存,提高反射性能 * * @author liuzh */ public class MetaObjectWithReflectCache { public static final ObjectFactory DEFAULT_OBJECT_FACTORY = new DefaultObjectFactory(); public static final ObjectWrapperFactory DEFAULT_OBJECT_WRAPPER_FACTORY = new DefaultObjectWrapperFactory(); public static final ReflectorFactory DEFAULT_REFLECTOR_FACTORY = new DefaultReflectorFactory(); public static MetaObject forObject(Object object) { try { return MetaObject.forObject(object, DEFAULT_OBJECT_FACTORY, DEFAULT_OBJECT_WRAPPER_FACTORY, DEFAULT_REFLECTOR_FACTORY); } catch (Exception e) { throw new PageException(e); } } } ================================================ FILE: src/main/java/com/github/pagehelper/util/PageObjectUtil.java ================================================ /* * The MIT License (MIT) * * Copyright (c) 2014-2023 abel533@gmail.com * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ package com.github.pagehelper.util; import com.github.pagehelper.IPage; import com.github.pagehelper.Page; import com.github.pagehelper.PageException; import org.apache.ibatis.reflection.MetaObject; import java.lang.reflect.Method; import java.util.HashMap; import java.util.Map; /** * 分页参数对象工具类 * * @author liuzh */ public abstract class PageObjectUtil { //request获取方法 protected static Boolean hasRequest; protected static Class requestClass; protected static Method getParameterMap; protected static Map PARAMS = new HashMap(6, 1); static { try { requestClass = ClassUtil.getServletRequestClass(); getParameterMap = requestClass.getMethod("getParameterMap", new Class[]{}); hasRequest = true; } catch (Throwable e) { hasRequest = false; } PARAMS.put("pageNum", "pageNum"); PARAMS.put("pageSize", "pageSize"); PARAMS.put("count", "countSql"); PARAMS.put("orderBy", "orderBy"); PARAMS.put("reasonable", "reasonable"); PARAMS.put("pageSizeZero", "pageSizeZero"); } /** * 对象中获取分页参数 * * @param params * @return */ public static Page getPageFromObject(Object params, boolean required) { if (params == null) { throw new PageException("unable to get paginated query parameters!"); } if(params instanceof IPage){ IPage pageParams = (IPage) params; Page page = null; if(pageParams.getPageNum() != null && pageParams.getPageSize() != null){ page = new Page(pageParams.getPageNum(), pageParams.getPageSize()); } if (StringUtil.isNotEmpty(pageParams.getOrderBy())) { if(page != null){ page.setOrderBy(pageParams.getOrderBy()); } else { page = new Page(); page.setOrderBy(pageParams.getOrderBy()); page.setOrderByOnly(true); } } return page; } int pageNum; int pageSize; MetaObject paramsObject = null; if (hasRequest && requestClass.isAssignableFrom(params.getClass())) { try { paramsObject = MetaObjectUtil.forObject(getParameterMap.invoke(params, new Object[]{})); } catch (Exception e) { //忽略 } } else { paramsObject = MetaObjectUtil.forObject(params); } if (paramsObject == null) { throw new PageException("The pagination query parameter failed to be processed!"); } Object orderBy = getParamValue(paramsObject, "orderBy", false); boolean hasOrderBy = false; if (orderBy != null && orderBy.toString().length() > 0) { hasOrderBy = true; } try { Object _pageNum = getParamValue(paramsObject, "pageNum", required); Object _pageSize = getParamValue(paramsObject, "pageSize", required); if (_pageNum == null || _pageSize == null) { if(hasOrderBy){ Page page = new Page(); page.setOrderBy(orderBy.toString()); page.setOrderByOnly(true); return page; } return null; } pageNum = Integer.parseInt(String.valueOf(_pageNum)); pageSize = Integer.parseInt(String.valueOf(_pageSize)); } catch (NumberFormatException e) { throw new PageException("pagination parameters are not a valid number type!", e); } Page page = new Page(pageNum, pageSize); //count查询 Object _count = getParamValue(paramsObject, "count", false); if (_count != null) { page.setCount(Boolean.valueOf(String.valueOf(_count))); } //排序 if (hasOrderBy) { page.setOrderBy(orderBy.toString()); } //分页合理化 Object reasonable = getParamValue(paramsObject, "reasonable", false); if (reasonable != null) { page.setReasonable(Boolean.valueOf(String.valueOf(reasonable))); } //查询全部 Object pageSizeZero = getParamValue(paramsObject, "pageSizeZero", false); if (pageSizeZero != null) { page.setPageSizeZero(Boolean.valueOf(String.valueOf(pageSizeZero))); } return page; } /** * 从对象中取参数 * * @param paramsObject * @param paramName * @param required * @return */ protected static Object getParamValue(MetaObject paramsObject, String paramName, boolean required) { Object value = null; if (paramsObject.hasGetter(PARAMS.get(paramName))) { value = paramsObject.getValue(PARAMS.get(paramName)); } if (value != null && value.getClass().isArray()) { Object[] values = (Object[]) value; if (values.length == 0) { value = null; } else { value = values[0]; } } if (required && value == null) { throw new PageException("Paginated queries are missing the necessary parameters:" + PARAMS.get(paramName)); } return value; } public static void setParams(String params) { if (StringUtil.isNotEmpty(params)) { String[] ps = params.split("[;|,|&]"); for (String s : ps) { String[] ss = s.split("[=|:]"); if (ss.length == 2) { PARAMS.put(ss[0], ss[1]); } } } } } ================================================ FILE: src/main/java/com/github/pagehelper/util/SqlSafeUtil.java ================================================ /* * The MIT License (MIT) * * Copyright (c) 2014-2023 abel533@gmail.com * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ package com.github.pagehelper.util; import java.util.regex.Pattern; /** * 更严格的SQL注入检测 */ public class SqlSafeUtil { /** * SQL语法检查正则:符合两个关键字(有先后顺序)才算匹配 *

* 参考: mybatis-plus-core/src/main/java/com/baomidou/mybatisplus/core/toolkit/sql/SqlInjectionUtils.java */ private static final Pattern SQL_SYNTAX_PATTERN = Pattern.compile("(insert|delete|update|select|create|drop|truncate|grant|alter|deny|revoke|call|execute|exec|declare|show|rename|set)" + "\\s+.*(into|from|set|where|table|database|view|index|on|cursor|procedure|trigger|for|password|union|and|or)|(select\\s*\\*\\s*from\\s+)", Pattern.CASE_INSENSITIVE); /** * 使用'、;或注释截断SQL检查正则 *

* 参考: mybatis-plus-core/src/main/java/com/baomidou/mybatisplus/core/toolkit/sql/SqlInjectionUtils.java */ private static final Pattern SQL_COMMENT_PATTERN = Pattern.compile("'.*(or|union|--|#|/*|;)", Pattern.CASE_INSENSITIVE); /** * 检查参数是否存在 SQL 注入 * * @param value 检查参数 * @return true 非法 false 合法 */ public static boolean check(String value) { if (value == null) { return false; } // 不允许使用任何函数(不能出现括号),否则无法检测后面这个注入 order by id,if(1=2,1,(sleep(100))); return value.contains("(") || SQL_COMMENT_PATTERN.matcher(value).find() || SQL_SYNTAX_PATTERN.matcher(value).find(); } } ================================================ FILE: src/main/java/com/github/pagehelper/util/StackTraceUtil.java ================================================ /* * The MIT License (MIT) * * Copyright (c) 2014-2023 abel533@gmail.com * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ package com.github.pagehelper.util; import java.io.PrintWriter; import java.io.StringWriter; public class StackTraceUtil { /** * 当前方法堆栈信息 */ public static String current() { Exception exception = new Exception("Stack information when setting pagination parameters"); StringWriter writer = new StringWriter(); exception.printStackTrace(new PrintWriter(writer)); return writer.toString(); } } ================================================ FILE: src/main/java/com/github/pagehelper/util/StringUtil.java ================================================ /* * The MIT License (MIT) * * Copyright (c) 2014-2023 abel533@gmail.com * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ package com.github.pagehelper.util; /** * @author liuzh * @since 4.1.0 */ public class StringUtil { public static boolean isEmpty(String str) { if (str == null || str.length() == 0) { return true; } return false; } public static boolean isNotEmpty(String str) { return !isEmpty(str); } } ================================================ FILE: src/test/java/com/github/pagehelper/mapper/ProviderMethod.java ================================================ /* * The MIT License (MIT) * * Copyright (c) 2014-2023 abel533@gmail.com * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ package com.github.pagehelper.mapper; import com.github.pagehelper.model.User; import java.util.HashMap; import java.util.Map; /** * @author liuzh */ public class ProviderMethod { public String selectSimple(String str) { return "select * from user where name like '%" + str + "'"; } @SuppressWarnings("unchecked") public String select(Map map) { Map param = (HashMap) map.get("param"); StringBuilder sbSql = new StringBuilder(); sbSql.append("select * from user where 1=1 "); for (Map.Entry entry : param.entrySet()) { sbSql.append(" and " + entry.getKey() + "= #{param." + entry.getKey() + "} "); } sbSql.append("order by id"); return sbSql.toString(); } public String selectUser(User user) { StringBuilder sbSql = new StringBuilder(); sbSql.append("select * from user where 1=1 "); if (user.getId() > 0) { sbSql.append(" and id = #{id} "); } if (user.getPy() != null) { sbSql.append(" and py = #{py} "); } if (user.getName() != null) { sbSql.append(" and name = #{name} "); } sbSql.append("order by id"); return sbSql.toString(); } } ================================================ FILE: src/test/java/com/github/pagehelper/mapper/UserMapper.java ================================================ /* * The MIT License (MIT) * * Copyright (c) 2014-2023 abel533@gmail.com * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ package com.github.pagehelper.mapper; import com.github.pagehelper.Page; import com.github.pagehelper.model.*; import com.github.pagehelper.test.basic.dynamic.Where; import org.apache.ibatis.annotations.Param; import org.apache.ibatis.annotations.Select; import org.apache.ibatis.annotations.SelectProvider; import org.apache.ibatis.session.RowBounds; import java.util.List; import java.util.Map; @SuppressWarnings("rawtypes") public interface UserMapper { @Select("select * from user order by ${order}") List selectByOrder(@Param("order") String order); // 增加Provider测试 @SelectProvider(type = ProviderMethod.class, method = "selectSimple") Page selectSimple(String str); // 增加Provider测试 @SelectProvider(type = ProviderMethod.class, method = "select") List selectByProvider(@Param("param") Map map); @SelectProvider(type = ProviderMethod.class, method = "selectUser") List selectByUserProvider(User user); @Select("Select * from user") List> selectBySelect(); List selectByOrder2(@Param("order") String order); List selectAll(); // 嵌套查询 List selectCollectionMap(); List selectGreterThanId(int id); List selectGreterThanIdAndNotEquelName(@Param("id") int id, @Param("name") String name); List selectAll(RowBounds rowBounds); List selectAllOrderby(); List selectAllOrderByParams(@Param("order1") String order1, @Param("order2") String order2); // 下面是三种参数类型的测试方法 List selectAllOrderByMap(Map orders); List selectAllOrderByList(List params); List selectAllOrderByArray(Integer[] params); // 测试动态sql,where/if List selectIf(@Param("id") Integer id); List selectIf3(User user); List selectIf2(@Param("id1") Integer id1, @Param("id2") Integer id2); List selectIf2List(@Param("id1") List id1, @Param("id2") List id2); List selectIf2ListAndOrder(@Param("id1") List id1, @Param("id2") List id2, @Param("order") String order); List selectChoose(@Param("id1") Integer id1, @Param("id2") Integer id2); List selectLike(User user); // 特殊sql语句的测试 - 主要测试count查询 List selectUnion(); List selectLeftjoin(); List selectWith(); // select column中包含参数时 List selectColumns(@Param("columns") String... columns); List selectMULId(int mul); // group by时 List selectGroupBy(); // select Map List selectByWhereMap(Where where); // Example List selectByExample(UserExample example); List selectDistinct(); List selectExists(); List selectByPageNumSize(@Param("pageNum") int pageNum, @Param("pageSize") int pageSize); List selectByPageNumSizeOrderBy(@Param("pageNum") int pageNum, @Param("pageSize") int pageSize, @Param("orderBy") String orderBy); List selectByOrderBy(@Param("orderBy") String orderBy); List selectByQueryModel(UserQueryModel queryModel); List selectByIdList(@Param("idList") List idList); List selectByIdList2(@Param("idList") List idList); List> execute(@Param("sql") String sql); List selectByCode(Code code); /** * Test for issue #868: ORDER BY with parameter binding */ List selectOrderByWithParam(@Param("py") String py); } ================================================ FILE: src/test/java/com/github/pagehelper/model/Code.java ================================================ /* * The MIT License (MIT) * * Copyright (c) 2014-2023 abel533@gmail.com * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ package com.github.pagehelper.model; /** * @author liuzh * @since 2017/5/30. */ public enum Code { LR, LQQ } ================================================ FILE: src/test/java/com/github/pagehelper/model/User.java ================================================ /* * The MIT License (MIT) * * Copyright (c) 2014-2023 abel533@gmail.com * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ package com.github.pagehelper.model; import java.io.Serializable; import java.util.List; /** * Description: User * Author: liuzh * Update: liuzh(2014-06-06 13:38) */ public class User implements Serializable { private static final long serialVersionUID = 6569081236403751407L; private int id; List users; private String name; private String py; public int getId() { return id; } public void setId(int id) { this.id = id; } @Override public String toString() { return "User{" + "id=" + id + ", name='" + name + '\'' + ", py='" + py + '\'' + ", user=" + users + '}'; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getPy() { return py; } public void setPy(String py) { this.py = py; } public List getUsers() { return users; } public void setUsers(List users) { this.users = users; } } ================================================ FILE: src/test/java/com/github/pagehelper/model/UserCode.java ================================================ /* * The MIT License (MIT) * * Copyright (c) 2014-2023 abel533@gmail.com * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ package com.github.pagehelper.model; import java.io.Serializable; import java.util.List; public class UserCode implements Serializable { private static final long serialVersionUID = 6569081236403751407L; private int id; List users; private String name; private Code py; public int getId() { return id; } public void setId(int id) { this.id = id; } public String getName() { return name; } public UserCode setName(String name) { this.name = name; return this; } public Code getPy() { return py; } public void setPy(Code py) { this.py = py; } public List getUsers() { return users; } public void setUsers(List users) { this.users = users; } } ================================================ FILE: src/test/java/com/github/pagehelper/model/UserExample.java ================================================ /* * The MIT License (MIT) * * Copyright (c) 2014-2023 abel533@gmail.com * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ package com.github.pagehelper.model; import java.util.ArrayList; import java.util.List; public class UserExample { protected String orderByClause; protected boolean distinct; protected List oredCriteria; public UserExample() { oredCriteria = new ArrayList(); } public void or(Criteria criteria) { oredCriteria.add(criteria); } public Criteria or() { Criteria criteria = createCriteriaInternal(); oredCriteria.add(criteria); return criteria; } public Criteria createCriteria() { Criteria criteria = createCriteriaInternal(); if (oredCriteria.size() == 0) { oredCriteria.add(criteria); } return criteria; } protected Criteria createCriteriaInternal() { Criteria criteria = new Criteria(); return criteria; } public void clear() { oredCriteria.clear(); orderByClause = null; distinct = false; } protected abstract static class GeneratedCriteria { protected List criteria; protected GeneratedCriteria() { super(); criteria = new ArrayList(); } protected void addCriterion(String condition) { if (condition == null) { throw new RuntimeException("Value for condition cannot be null"); } criteria.add(new Criterion(condition)); } protected void addCriterion(String condition, Object value, String property) { if (value == null) { throw new RuntimeException("Value for " + property + " cannot be null"); } criteria.add(new Criterion(condition, value)); } protected void addCriterion(String condition, Object value1, Object value2, String property) { if (value1 == null || value2 == null) { throw new RuntimeException("Between values for " + property + " cannot be null"); } criteria.add(new Criterion(condition, value1, value2)); } public Criteria andIdIsNull() { addCriterion("Id is null"); return (Criteria) this; } public Criteria andIdIsNotNull() { addCriterion("Id is not null"); return (Criteria) this; } public Criteria andIdEqualTo(Integer value) { addCriterion("Id =", value, "id"); return (Criteria) this; } public Criteria andIdNotEqualTo(Integer value) { addCriterion("Id <>", value, "id"); return (Criteria) this; } public Criteria andIdGreaterThan(Integer value) { addCriterion("Id >", value, "id"); return (Criteria) this; } public Criteria andIdGreaterThanOrEqualTo(Integer value) { addCriterion("Id >=", value, "id"); return (Criteria) this; } public Criteria andIdLessThan(Integer value) { addCriterion("Id <", value, "id"); return (Criteria) this; } public Criteria andIdLessThanOrEqualTo(Integer value) { addCriterion("Id <=", value, "id"); return (Criteria) this; } public Criteria andIdIn(List values) { addCriterion("Id in", values, "id"); return (Criteria) this; } public Criteria andIdNotIn(List values) { addCriterion("Id not in", values, "id"); return (Criteria) this; } public Criteria andIdBetween(Integer value1, Integer value2) { addCriterion("Id between", value1, value2, "id"); return (Criteria) this; } public Criteria andIdNotBetween(Integer value1, Integer value2) { addCriterion("Id not between", value1, value2, "id"); return (Criteria) this; } public Criteria andUsernameIsNull() { addCriterion("name is null"); return (Criteria) this; } public Criteria andUsernameIsNotNull() { addCriterion("name is not null"); return (Criteria) this; } public Criteria andUsernameEqualTo(String value) { addCriterion("name =", value, "name"); return (Criteria) this; } public Criteria andUsernameNotEqualTo(String value) { addCriterion("name <>", value, "name"); return (Criteria) this; } public Criteria andUsernameGreaterThan(String value) { addCriterion("name >", value, "name"); return (Criteria) this; } public Criteria andUsernameGreaterThanOrEqualTo(String value) { addCriterion("name >=", value, "name"); return (Criteria) this; } public Criteria andUsernameLessThan(String value) { addCriterion("name <", value, "name"); return (Criteria) this; } public Criteria andUsernameLessThanOrEqualTo(String value) { addCriterion("name <=", value, "name"); return (Criteria) this; } public Criteria andUsernameLike(String value) { addCriterion("name like", value, "name"); return (Criteria) this; } public Criteria andUsernameNotLike(String value) { addCriterion("name not like", value, "name"); return (Criteria) this; } public Criteria andUsernameIn(List values) { addCriterion("name in", values, "name"); return (Criteria) this; } public Criteria andUsernameNotIn(List values) { addCriterion("name not in", values, "name"); return (Criteria) this; } public Criteria andUsernameBetween(String value1, String value2) { addCriterion("name between", value1, value2, "name"); return (Criteria) this; } public Criteria andUsernameNotBetween(String value1, String value2) { addCriterion("name not between", value1, value2, "name"); return (Criteria) this; } public Criteria andUsercodeIsNull() { addCriterion("py is null"); return (Criteria) this; } public Criteria andUsercodeIsNotNull() { addCriterion("py is not null"); return (Criteria) this; } public Criteria andUsercodeEqualTo(String value) { addCriterion("py =", value, "py"); return (Criteria) this; } public Criteria andUsercodeNotEqualTo(String value) { addCriterion("py <>", value, "py"); return (Criteria) this; } public Criteria andUsercodeGreaterThan(String value) { addCriterion("py >", value, "py"); return (Criteria) this; } public Criteria andUsercodeGreaterThanOrEqualTo(String value) { addCriterion("py >=", value, "py"); return (Criteria) this; } public Criteria andUsercodeLessThan(String value) { addCriterion("py <", value, "py"); return (Criteria) this; } public Criteria andUsercodeLessThanOrEqualTo(String value) { addCriterion("py <=", value, "py"); return (Criteria) this; } public Criteria andUsercodeLike(String value) { addCriterion("py like", value, "py"); return (Criteria) this; } public Criteria andUsercodeNotLike(String value) { addCriterion("py not like", value, "py"); return (Criteria) this; } public Criteria andUsercodeIn(List values) { addCriterion("py in", values, "py"); return (Criteria) this; } public Criteria andUsercodeNotIn(List values) { addCriterion("py not in", values, "py"); return (Criteria) this; } public Criteria andUsercodeBetween(String value1, String value2) { addCriterion("py between", value1, value2, "py"); return (Criteria) this; } public Criteria andUsercodeNotBetween(String value1, String value2) { addCriterion("py not between", value1, value2, "py"); return (Criteria) this; } public List getAllCriteria() { return criteria; } public List getCriteria() { return criteria; } public boolean isValid() { return criteria.size() > 0; } } public static class Criteria extends GeneratedCriteria { protected Criteria() { super(); } } public static class Criterion { private String condition; private Object value; private Object secondValue; private boolean noValue; private boolean singleValue; private boolean betweenValue; private boolean listValue; private String typeHandler; protected Criterion(String condition) { super(); this.condition = condition; this.typeHandler = null; this.noValue = true; } protected Criterion(String condition, Object value, String typeHandler) { super(); this.condition = condition; this.value = value; this.typeHandler = typeHandler; if (value instanceof List) { this.listValue = true; } else { this.singleValue = true; } } protected Criterion(String condition, Object value) { this(condition, value, null); } protected Criterion(String condition, Object value, Object secondValue, String typeHandler) { super(); this.condition = condition; this.value = value; this.secondValue = secondValue; this.typeHandler = typeHandler; this.betweenValue = true; } protected Criterion(String condition, Object value, Object secondValue) { this(condition, value, secondValue, null); } public String getCondition() { return condition; } public Object getSecondValue() { return secondValue; } public String getTypeHandler() { return typeHandler; } public Object getValue() { return value; } public boolean isBetweenValue() { return betweenValue; } public boolean isListValue() { return listValue; } public boolean isNoValue() { return noValue; } public boolean isSingleValue() { return singleValue; } } public String getOrderByClause() { return orderByClause; } public void setOrderByClause(String orderByClause) { this.orderByClause = orderByClause; } public List getOredCriteria() { return oredCriteria; } public boolean isDistinct() { return distinct; } public void setDistinct(boolean distinct) { this.distinct = distinct; } } ================================================ FILE: src/test/java/com/github/pagehelper/model/UserQueryModel.java ================================================ /* * The MIT License (MIT) * * Copyright (c) 2014-2023 abel533@gmail.com * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ package com.github.pagehelper.model; /** * @author liuzh * @since 2015-11-07 14:39 */ public class UserQueryModel { private Integer pageNum; private Integer pageSize; private String orderBy; public String getOrderBy() { return orderBy; } public void setOrderBy(String orderBy) { this.orderBy = orderBy; } public Integer getPageNum() { return pageNum; } public void setPageNum(Integer pageNum) { this.pageNum = pageNum; } public Integer getPageSize() { return pageSize; } public void setPageSize(Integer pageSize) { this.pageSize = pageSize; } } ================================================ FILE: src/test/java/com/github/pagehelper/rowbounds/RowBoundsHelper.java ================================================ /* * The MIT License (MIT) * * Copyright (c) 2014-2023 abel533@gmail.com * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ package com.github.pagehelper.rowbounds; import org.apache.ibatis.io.Resources; import org.apache.ibatis.jdbc.ScriptRunner; import org.apache.ibatis.session.SqlSession; import org.apache.ibatis.session.SqlSessionFactory; import org.apache.ibatis.session.SqlSessionFactoryBuilder; import java.io.IOException; import java.io.Reader; import java.sql.Connection; public class RowBoundsHelper { private static SqlSessionFactory sqlSessionFactory; static { try { //创建SqlSessionFactory Reader reader = Resources.getResourceAsReader("rowbounds/mybatis-config.xml"); sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader); reader.close(); //创建数据库 SqlSession session = null; try { session = sqlSessionFactory.openSession(); Connection conn = session.getConnection(); reader = Resources.getResourceAsReader("rowbounds/hsqldb.sql"); ScriptRunner runner = new ScriptRunner(conn); runner.setLogWriter(null); runner.runScript(reader); reader.close(); } finally { if (session != null) { session.close(); } } } catch (IOException e) { e.printStackTrace(); } } /** * 获取Session * * @return */ public static SqlSession getSqlSession() { return sqlSessionFactory.openSession(); } } ================================================ FILE: src/test/java/com/github/pagehelper/rowbounds/test/PageRowBoundsTest.java ================================================ /* * The MIT License (MIT) * * Copyright (c) 2014-2023 abel533@gmail.com * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ package com.github.pagehelper.rowbounds.test; import com.github.pagehelper.PageRowBounds; import com.github.pagehelper.mapper.UserMapper; import com.github.pagehelper.model.User; import com.github.pagehelper.rowbounds.RowBoundsHelper; import org.apache.ibatis.session.SqlSession; import org.junit.Test; import java.util.HashMap; import java.util.List; import java.util.Map; import static org.junit.Assert.assertEquals; public class PageRowBoundsTest { /** * 使用Mapper接口调用时,对接口增加RowBounds参数,不需要修改对应的xml配置(或注解配置) *

* RowBounds方式不进行count查询,可以通过修改Page代码实现 *

* 这种情况下如果同时使用startPage方法,以startPage为准 */ @Test public void testMapperWithPageRowBounds() { SqlSession sqlSession = RowBoundsHelper.getSqlSession(); UserMapper userMapper = sqlSession.getMapper(UserMapper.class); try { //获取第1页,10条内容,默认查询总数count PageRowBounds pageRowBounds = new PageRowBounds(0, 10); List list = userMapper.selectAll(pageRowBounds); //新增PageInfo对象,对返回结果进行封装 assertEquals(10, list.size()); assertEquals(183L, pageRowBounds.getTotal().longValue()); //判断查询结果的位置是否正确 assertEquals(1, list.get(0).getId()); assertEquals(10, list.get(list.size() - 1).getId()); //获取第10页,10条内容,显式查询总数count pageRowBounds = new PageRowBounds(90, 10); list = userMapper.selectAll(pageRowBounds); assertEquals(10, list.size()); assertEquals(183L, pageRowBounds.getTotal().longValue()); //判断查询结果的位置是否正确 assertEquals(91, list.get(0).getId()); assertEquals(100, list.get(list.size() - 1).getId()); //获取第3页,20条内容,默认查询总数count pageRowBounds = new PageRowBounds(100, 20); list = userMapper.selectAll(pageRowBounds); assertEquals(20, list.size()); assertEquals(183L, pageRowBounds.getTotal().longValue()); //判断查询结果的位置是否正确 assertEquals(101, list.get(0).getId()); assertEquals(120, list.get(list.size() - 1).getId()); } finally { sqlSession.close(); } } /** * 使用命名空间方式的RowBounds进行分页,使用RowBounds时不进行count查询 * 通过修改代码可以进行count查询,没法通过其他方法改变参数 * 因为如果通过调用一个别的方法来标记count查询,还不如直接startPage *

* 同时使用startPage时,以startPage为准,会根据startPage参数来查询 */ @Test public void testNamespaceWithPageRowBounds() { SqlSession sqlSession = RowBoundsHelper.getSqlSession(); try { //获取从0开始,10条内容 PageRowBounds pageRowBounds = new PageRowBounds(0, 10); List list = sqlSession.selectList("selectAll", null, pageRowBounds); assertEquals(10, list.size()); assertEquals(183L, pageRowBounds.getTotal().longValue()); //判断查询结果的位置是否正确 assertEquals(1, list.get(0).getId()); assertEquals(10, list.get(list.size() - 1).getId()); //获取从10开始,10条内容 pageRowBounds = new PageRowBounds(90, 10); list = sqlSession.selectList("selectAll", null, pageRowBounds); assertEquals(10, list.size()); assertEquals(183L, pageRowBounds.getTotal().longValue()); //判断查询结果的位置是否正确 assertEquals(91, list.get(0).getId()); assertEquals(100, list.get(list.size() - 1).getId()); //获取从20开始,20条内容 pageRowBounds = new PageRowBounds(100, 20); list = sqlSession.selectList("selectAll", null, pageRowBounds); assertEquals(20, list.size()); assertEquals(183L, pageRowBounds.getTotal().longValue()); //判断查询结果的位置是否正确 assertEquals(101, list.get(0).getId()); assertEquals(120, list.get(list.size() - 1).getId()); } finally { sqlSession.close(); } } @Test public void testNamespaceWithRowBounds2() { SqlSession sqlSession = RowBoundsHelper.getSqlSession(); try { //获取从0开始,10条内容 PageRowBounds pageRowBounds = new PageRowBounds(0, 10); List list = sqlSession.selectList("selectIf", null, pageRowBounds); assertEquals(10, list.size()); assertEquals(183L, pageRowBounds.getTotal().longValue()); //判断查询结果的位置是否正确 assertEquals(1, list.get(0).getId()); assertEquals(10, list.get(list.size() - 1).getId()); Map map = new HashMap(); map.put("id", 10); //获取从10开始,10条内容 pageRowBounds = new PageRowBounds(90, 10); list = sqlSession.selectList("selectIf", map, pageRowBounds); assertEquals(10, list.size()); assertEquals(173L, pageRowBounds.getTotal().longValue()); //判断查询结果的位置是否正确 assertEquals(101, list.get(0).getId()); assertEquals(110, list.get(list.size() - 1).getId()); } finally { sqlSession.close(); } } /** * 使用Mapper接口调用时,使用PageHelper.startPage效果更好,不需要添加Mapper接口参数 */ @Test public void testWithRowboundsAndCountTrue() { SqlSession sqlSession = RowBoundsHelper.getSqlSession(); UserMapper userMapper = sqlSession.getMapper(UserMapper.class); try { //limit=0,这时候相当于用分页插件求count,但是前提必须是配置rounbounds方式求count,否则都是-1 //这里由于没有配置,应该都是-1 PageRowBounds pageRowBounds = new PageRowBounds(0, -1); List list = userMapper.selectAll(pageRowBounds); assertEquals(183, list.size()); //pageSize<0的时候同上 list = userMapper.selectAll(new PageRowBounds(0, -100)); assertEquals(183, list.size()); } finally { sqlSession.close(); } } class IdBean { private Integer id; public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } } } ================================================ FILE: src/test/java/com/github/pagehelper/rowbounds/test/RowBoundsTest.java ================================================ /* * The MIT License (MIT) * * Copyright (c) 2014-2023 abel533@gmail.com * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ package com.github.pagehelper.rowbounds.test; import com.github.pagehelper.mapper.UserMapper; import com.github.pagehelper.model.User; import com.github.pagehelper.rowbounds.RowBoundsHelper; import org.apache.ibatis.session.RowBounds; import org.apache.ibatis.session.SqlSession; import org.junit.Test; import java.util.HashMap; import java.util.List; import java.util.Map; import static org.junit.Assert.assertEquals; public class RowBoundsTest { /** * 使用Mapper接口调用时,对接口增加RowBounds参数,不需要修改对应的xml配置(或注解配置) *

* RowBounds方式不进行count查询,可以通过修改Page代码实现 *

* 这种情况下如果同时使用startPage方法,以startPage为准 */ @Test public void testMapperWithRowBounds() { SqlSession sqlSession = RowBoundsHelper.getSqlSession(); UserMapper userMapper = sqlSession.getMapper(UserMapper.class); try { //获取第1页,10条内容,默认查询总数count List list = userMapper.selectAll(new RowBounds(0, 10)); //新增PageInfo对象,对返回结果进行封装 assertEquals(10, list.size()); //判断查询结果的位置是否正确 assertEquals(1, list.get(0).getId()); assertEquals(10, list.get(list.size() - 1).getId()); //获取第10页,10条内容,显式查询总数count list = userMapper.selectAll(new RowBounds(90, 10)); assertEquals(10, list.size()); //判断查询结果的位置是否正确 assertEquals(91, list.get(0).getId()); assertEquals(100, list.get(list.size() - 1).getId()); //获取第3页,20条内容,默认查询总数count list = userMapper.selectAll(new RowBounds(100, 20)); assertEquals(20, list.size()); //判断查询结果的位置是否正确 assertEquals(101, list.get(0).getId()); assertEquals(120, list.get(list.size() - 1).getId()); } finally { sqlSession.close(); } } /** * 使用命名空间方式的RowBounds进行分页,使用RowBounds时不进行count查询 * 通过修改代码可以进行count查询,没法通过其他方法改变参数 * 因为如果通过调用一个别的方法来标记count查询,还不如直接startPage *

* 同时使用startPage时,以startPage为准,会根据startPage参数来查询 */ @Test public void testNamespaceWithRowBounds() { SqlSession sqlSession = RowBoundsHelper.getSqlSession(); try { //获取从0开始,10条内容 List list = sqlSession.selectList("selectAll", null, new RowBounds(0, 10)); assertEquals(10, list.size()); //判断查询结果的位置是否正确 assertEquals(1, list.get(0).getId()); assertEquals(10, list.get(list.size() - 1).getId()); //获取从10开始,10条内容 list = sqlSession.selectList("selectAll", null, new RowBounds(90, 10)); assertEquals(10, list.size()); //判断查询结果的位置是否正确 assertEquals(91, list.get(0).getId()); assertEquals(100, list.get(list.size() - 1).getId()); //获取从20开始,20条内容 list = sqlSession.selectList("selectAll", null, new RowBounds(100, 20)); assertEquals(20, list.size()); //判断查询结果的位置是否正确 assertEquals(101, list.get(0).getId()); assertEquals(120, list.get(list.size() - 1).getId()); } finally { sqlSession.close(); } } @Test public void testNamespaceWithRowBounds2() { SqlSession sqlSession = RowBoundsHelper.getSqlSession(); try { //获取从0开始,10条内容 List list = sqlSession.selectList("selectIf", null, new RowBounds(0, 10)); assertEquals(10, list.size()); //判断查询结果的位置是否正确 assertEquals(1, list.get(0).getId()); assertEquals(10, list.get(list.size() - 1).getId()); Map map = new HashMap(); map.put("id", 10); //获取从10开始,10条内容 list = sqlSession.selectList("selectIf", map, new RowBounds(90, 10)); assertEquals(10, list.size()); //判断查询结果的位置是否正确 assertEquals(101, list.get(0).getId()); assertEquals(110, list.get(list.size() - 1).getId()); } finally { sqlSession.close(); } } /** * 使用Mapper接口调用时,使用PageHelper.startPage效果更好,不需要添加Mapper接口参数 */ @Test public void testWithRowboundsAndCountTrue() { SqlSession sqlSession = RowBoundsHelper.getSqlSession(); UserMapper userMapper = sqlSession.getMapper(UserMapper.class); try { //limit=0,这时候相当于用分页插件求count,但是前提必须是配置rounbounds方式求count,否则都是-1 //这里由于没有配置,应该都是-1 List list = userMapper.selectAll(new RowBounds(0, -1)); assertEquals(183, list.size()); //pageSize<0的时候同上 list = userMapper.selectAll(new RowBounds(0, -100)); assertEquals(183, list.size()); } finally { sqlSession.close(); } } class IdBean { private Integer id; public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } } } ================================================ FILE: src/test/java/com/github/pagehelper/sql/DefaultOrderBySqlParserTest.java ================================================ /* * The MIT License (MIT) * * Copyright (c) 2014-2023 abel533@gmail.com * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ package com.github.pagehelper.sql; import com.github.pagehelper.parser.OrderBySqlParser; import com.github.pagehelper.parser.defaults.DefaultOrderBySqlParser; import org.junit.Assert; import org.junit.Test; public class DefaultOrderBySqlParserTest { private OrderBySqlParser orderBySqlParser = new DefaultOrderBySqlParser(); @Test public void testOrderBy() { String sql = orderBySqlParser.converToOrderBySql("select * from user where length(name) > 0 order by id desc", "name desc"); Assert.assertEquals("SELECT * FROM user WHERE length(name) > 0 order by name desc", sql); } } ================================================ FILE: src/test/java/com/github/pagehelper/sql/SqlServerTest.java ================================================ /* * The MIT License (MIT) * * Copyright (c) 2014-2023 abel533@gmail.com * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ package com.github.pagehelper.sql; import com.github.pagehelper.dialect.ReplaceSql; import com.github.pagehelper.dialect.replace.RegexWithNolockReplaceSql; import com.github.pagehelper.parser.CountSqlParser; import com.github.pagehelper.parser.SqlServerSqlParser; import com.github.pagehelper.parser.defaults.DefaultCountSqlParser; import com.github.pagehelper.parser.defaults.DefaultSqlServerSqlParser; import org.junit.Assert; import org.junit.Test; /** * @author liuzh */ public class SqlServerTest { public static final SqlServerSqlParser sqlServer = new DefaultSqlServerSqlParser(); CountSqlParser countSqlParser = new DefaultCountSqlParser(); @Test public void testSqlTestWithlock() { String originalSql = "select * from Agency with (NOLOCK) where status=0 order by CreateTime"; Assert.assertEquals("SELECT TOP 10 * FROM (SELECT ROW_NUMBER() OVER (ORDER BY CreateTime) PAGE_ROW_NUMBER, * FROM (SELECT * FROM Agency WITH (NOLOCK) WHERE status = 0) AS PAGE_TABLE_ALIAS) AS PAGE_TABLE_ALIAS WHERE PAGE_ROW_NUMBER > 1 ORDER BY PAGE_ROW_NUMBER", sqlServer.convertToPageSql(originalSql, 1, 10)); } @Test public void testSqlTest() { String originalSql = "Select * from user o where id > 10 order by id desc , name asc"; Assert.assertEquals("SELECT TOP 10 * FROM (SELECT ROW_NUMBER() OVER (ORDER BY id DESC, name ASC) PAGE_ROW_NUMBER, * FROM (SELECT * FROM user o WHERE id > 10) AS PAGE_TABLE_ALIAS) AS PAGE_TABLE_ALIAS WHERE PAGE_ROW_NUMBER > 1 ORDER BY PAGE_ROW_NUMBER", sqlServer.convertToPageSql(originalSql, 1, 10)); } @Test public void testSqlAlias() { String originalSql = "Select o.* from user o where id > 10 order by id desc , name asc"; Assert.assertEquals("SELECT TOP 10 * FROM (SELECT ROW_NUMBER() OVER (ORDER BY id DESC, name ASC) PAGE_ROW_NUMBER, * FROM (SELECT o.* FROM user o WHERE id > 10) AS PAGE_TABLE_ALIAS) AS PAGE_TABLE_ALIAS WHERE PAGE_ROW_NUMBER > 1 ORDER BY PAGE_ROW_NUMBER", sqlServer.convertToPageSql(originalSql, 1, 10)); } @Test public void testSqlOrderByAlias() { String originalSql = "select py code from user order by code"; Assert.assertEquals("SELECT TOP 10 code FROM (SELECT ROW_NUMBER() OVER (ORDER BY code) PAGE_ROW_NUMBER, code FROM (SELECT py code FROM user) AS PAGE_TABLE_ALIAS) AS PAGE_TABLE_ALIAS WHERE PAGE_ROW_NUMBER > 1 ORDER BY PAGE_ROW_NUMBER", sqlServer.convertToPageSql(originalSql, 1, 10)); } @Test public void testSqlDistinct() { String originalSql = "select distinct py,name from user order by py"; Assert.assertEquals("SELECT TOP 10 py, name FROM (SELECT ROW_NUMBER() OVER (ORDER BY py) PAGE_ROW_NUMBER, py, name FROM (SELECT DISTINCT py, name FROM user) AS PAGE_TABLE_ALIAS) AS PAGE_TABLE_ALIAS WHERE PAGE_ROW_NUMBER > 1 ORDER BY PAGE_ROW_NUMBER", sqlServer.convertToPageSql(originalSql, 1, 10)); } @Test public void testSqlTableAll() { String originalSql = "Select user.* from user where id > 10 order by id desc , name asc"; Assert.assertEquals("SELECT TOP 10 * FROM (SELECT ROW_NUMBER() OVER (ORDER BY id DESC, name ASC) PAGE_ROW_NUMBER, * FROM (SELECT user.* FROM user WHERE id > 10) AS PAGE_TABLE_ALIAS) AS PAGE_TABLE_ALIAS WHERE PAGE_ROW_NUMBER > 1 ORDER BY PAGE_ROW_NUMBER", sqlServer.convertToPageSql(originalSql, 1, 10)); } @Test public void testSqlAs() { String originalSql = "Select id as id,name name,py as code from user o where id > 10 order by id desc , name asc"; Assert.assertEquals("SELECT TOP 10 id, name, code FROM (SELECT ROW_NUMBER() OVER (ORDER BY id DESC, name ASC) PAGE_ROW_NUMBER, id, name, code FROM (SELECT id AS id, name name, py AS code FROM user o WHERE id > 10) AS PAGE_TABLE_ALIAS) AS PAGE_TABLE_ALIAS WHERE PAGE_ROW_NUMBER > 1 ORDER BY PAGE_ROW_NUMBER", sqlServer.convertToPageSql(originalSql, 1, 10)); } @Test public void testSelectParameter() { //TODO 这种情况会增加?的个数,需要实际在Mybatis中测试 String originalSql = "Select id as id,? name,? from user o where id > 10 order by id desc , name asc"; Assert.assertEquals("SELECT TOP 10 id, name, ? FROM (SELECT ROW_NUMBER() OVER (ORDER BY id DESC, name ASC) PAGE_ROW_NUMBER, id, name, ? FROM (SELECT id AS id, ? name, ? FROM user o WHERE id > 10) AS PAGE_TABLE_ALIAS) AS PAGE_TABLE_ALIAS WHERE PAGE_ROW_NUMBER > 1 ORDER BY PAGE_ROW_NUMBER", sqlServer.convertToPageSql(originalSql, 1, 10)); } @Test public void testSqlWith() { String originalSql = "with cr as " + " (select id " + " from user " + " where id > 100 " + " and id < 120) " + "select id, name, py " + " from user " + " where id in (select * from cr) order by id"; Assert.assertEquals("WITH cr AS (SELECT id FROM user WHERE id > 100 AND id < 120) SELECT TOP 10 id, name, py FROM (SELECT ROW_NUMBER() OVER (ORDER BY id) PAGE_ROW_NUMBER, id, name, py FROM (SELECT id, name, py FROM user WHERE id IN (SELECT * FROM cr)) AS PAGE_TABLE_ALIAS) AS PAGE_TABLE_ALIAS WHERE PAGE_ROW_NUMBER > 1 ORDER BY PAGE_ROW_NUMBER", sqlServer.convertToPageSql(originalSql, 1, 10)); } @Test public void testSqlLeftJoin() { String originalSql = "select * " + " from (select distinct A.USERID, " + " A.USERCODE, " + " A.USERNAME, " + " A.USERPWD, " + " A.CREATEDATE, " + " A.UPDATEDATE, " + " A.USERSTATE, " + " A.MEMO, " + " A.USERPHONE, " + " A.USEREMAIL, " + " A.IDCARD, " + " D.DEPTNAME, " + " D.DEPTID " + " from BASE_SYS_USER A " + " left JOIN BASE_SYS_ROLE_USER_REL B " + " ON A.USERID = B.USERID " + " left JOIN BASE_SYS_ROLE C " + " on C.ROLEID = B.ROLEID " + " left join BASE_SYS_DEPT_USER_REL REL " + " on REL.USERID = A.USERID " + " left join BASE_SYS_DEPT D " + " on D.DEPTID = REL.DEPTID " + " where 1 = 1 " + " and C.ROLEID = ? " + " and D.DEPTID = ? " + " and A.USERNAME LIKE '%heh%' " + " and A.USERSTATE = ? " + " ) A Order by A.createDate desc"; Assert.assertEquals("SELECT TOP 10 * FROM (SELECT ROW_NUMBER() OVER (ORDER BY createDate DESC) PAGE_ROW_NUMBER, * FROM (SELECT * FROM (SELECT DISTINCT A.USERID, A.USERCODE, A.USERNAME, A.USERPWD, A.CREATEDATE, A.UPDATEDATE, A.USERSTATE, A.MEMO, A.USERPHONE, A.USEREMAIL, A.IDCARD, D.DEPTNAME, D.DEPTID FROM BASE_SYS_USER A LEFT JOIN BASE_SYS_ROLE_USER_REL B ON A.USERID = B.USERID LEFT JOIN BASE_SYS_ROLE C ON C.ROLEID = B.ROLEID LEFT JOIN BASE_SYS_DEPT_USER_REL REL ON REL.USERID = A.USERID LEFT JOIN BASE_SYS_DEPT D ON D.DEPTID = REL.DEPTID WHERE 1 = 1 AND C.ROLEID = ? AND D.DEPTID = ? AND A.USERNAME LIKE '%heh%' AND A.USERSTATE = ?) A) AS PAGE_TABLE_ALIAS) AS PAGE_TABLE_ALIAS WHERE PAGE_ROW_NUMBER > 1 ORDER BY PAGE_ROW_NUMBER", sqlServer.convertToPageSql(originalSql, 1, 10)); } @Test public void testSqlUnion() { String originalSql = "select name,py code from user where id >170 " + "union all " + "select name,py code from user where id < 10 order by code"; Assert.assertEquals("SELECT TOP 10 name, code FROM (SELECT ROW_NUMBER() OVER (ORDER BY code) PAGE_ROW_NUMBER, name, code FROM (SELECT name, code FROM (SELECT name, py code FROM user WHERE id > 170 UNION ALL SELECT name, py code FROM user WHERE id < 10) AS WRAP_OUTER_TABLE) AS PAGE_TABLE_ALIAS) AS PAGE_TABLE_ALIAS WHERE PAGE_ROW_NUMBER > 1 ORDER BY PAGE_ROW_NUMBER", sqlServer.convertToPageSql(originalSql, 1, 10)); } @Test public void testSqlUnion2() { String originalSql = "select name,code from ( " + "\tselect name,py code from user where id >170 " + "\tunion all " + "\tselect name,py code from user where id < 10 " + ") as temp " + "order by code"; Assert.assertEquals("SELECT TOP 10 name, code FROM (SELECT ROW_NUMBER() OVER (ORDER BY code) PAGE_ROW_NUMBER, name, code FROM (SELECT name, code FROM (SELECT name, py code FROM user WHERE id > 170 UNION ALL SELECT name, py code FROM user WHERE id < 10) AS temp) AS PAGE_TABLE_ALIAS) AS PAGE_TABLE_ALIAS WHERE PAGE_ROW_NUMBER > 1 ORDER BY PAGE_ROW_NUMBER", sqlServer.convertToPageSql(originalSql, 1, 10)); } @Test public void testSqlOrderByFunctionAlias() { String originalSql = "select py code, func() func_alias from user order by func()"; Assert.assertEquals("SELECT TOP 10 code, func_alias FROM (SELECT ROW_NUMBER() OVER (ORDER BY func_alias) PAGE_ROW_NUMBER, code, func_alias FROM (SELECT py code, func() func_alias FROM user) AS PAGE_TABLE_ALIAS) AS PAGE_TABLE_ALIAS WHERE PAGE_ROW_NUMBER > 1 ORDER BY PAGE_ROW_NUMBER", sqlServer.convertToPageSql(originalSql, 1, 10)); } @Test public void testSqlOrderByUnknown() { String originalSql = "select name from user order by py"; Assert.assertEquals("SELECT TOP 10 name FROM (SELECT ROW_NUMBER() OVER (ORDER BY ROW_ALIAS_1) PAGE_ROW_NUMBER, name FROM (SELECT name, py AS ROW_ALIAS_1 FROM user) AS PAGE_TABLE_ALIAS) AS PAGE_TABLE_ALIAS WHERE PAGE_ROW_NUMBER > 1 ORDER BY PAGE_ROW_NUMBER", sqlServer.convertToPageSql(originalSql, 1, 10)); } @Test public void testSqlOrderByTable() { String originalSql = "select t.py, t.name from user t order by t.py"; Assert.assertEquals("SELECT TOP 10 py, name FROM (SELECT ROW_NUMBER() OVER (ORDER BY py) PAGE_ROW_NUMBER, py, name FROM (SELECT t.py, t.name FROM user t) AS PAGE_TABLE_ALIAS) AS PAGE_TABLE_ALIAS WHERE PAGE_ROW_NUMBER > 1 ORDER BY PAGE_ROW_NUMBER", sqlServer.convertToPageSql(originalSql, 1, 10)); } @Test public void testSqlStar() { String originalSql = "select t.*, 1 alias from user t order by t.py"; Assert.assertEquals("SELECT TOP 10 * FROM (SELECT ROW_NUMBER() OVER (ORDER BY py) PAGE_ROW_NUMBER, * FROM (SELECT t.*, 1 alias FROM user t) AS PAGE_TABLE_ALIAS) AS PAGE_TABLE_ALIAS WHERE PAGE_ROW_NUMBER > 1 ORDER BY PAGE_ROW_NUMBER", sqlServer.convertToPageSql(originalSql, 1, 10)); } /** * JSqlParser的4.4版本对于 UR RS RR CS 作为别名解析错误 * 故将UR更改为SUR *

* 详见:https://github.com/JSQLParser/JSqlParser/issues/1520 */ @Test public void testSql377() { String originalSql = "select distinct u.user_id, u.dept_id, u.login_name, u.user_name, u.email, u.phonenumber, u.status, u.create_time from sys_user u left join sys_dept d on u.dept_id = d.dept_id left join sys_user_role sur on u.user_id = sur.user_id left join sys_role r on r.role_id = sur.role_id where u.del_flag = '0' and (r.role_id != 1 or r.role_id IS NULL) and u.user_id not in (select u.user_id from sys_user u inner join sys_user_role sur on u.user_id = sur.user_id and sur.role_id = 1)"; Assert.assertEquals("SELECT TOP 10 user_id, dept_id, login_name, user_name, email, phonenumber, status, create_time FROM (SELECT ROW_NUMBER() OVER (ORDER BY RAND()) PAGE_ROW_NUMBER, user_id, dept_id, login_name, user_name, email, phonenumber, status, create_time FROM (SELECT DISTINCT u.user_id, u.dept_id, u.login_name, u.user_name, u.email, u.phonenumber, u.status, u.create_time FROM sys_user u LEFT JOIN sys_dept d ON u.dept_id = d.dept_id LEFT JOIN sys_user_role sur ON u.user_id = sur.user_id LEFT JOIN sys_role r ON r.role_id = sur.role_id WHERE u.del_flag = '0' AND (r.role_id != 1 OR r.role_id IS NULL) AND u.user_id NOT IN (SELECT u.user_id FROM sys_user u INNER JOIN sys_user_role sur ON u.user_id = sur.user_id AND sur.role_id = 1)) AS PAGE_TABLE_ALIAS) AS PAGE_TABLE_ALIAS WHERE PAGE_ROW_NUMBER > 1 ORDER BY PAGE_ROW_NUMBER", sqlServer.convertToPageSql(originalSql, 1, 10)); } @Test public void testSql386() { String originalSql = " select a.Guid,\n" + " ProManager,\n" + " WorkOrderType,\n" + " a.Name,\n" + " WorkNote,\n" + " b.Name TeamName,\n" + " ConstructionSite,\n" + " iif(a.MaterialGuid is null, 0, 1) as IsMaterial,\n" + " a.MaterialGuid,\n" + " c.Code as MaterialCode,\n" + " c.FullName MaterialName,\n" + " d.FullName MatStdSortName\n" + " from RMC_WorkOrder a\n" + " left join dbo.SYS_OrgFrame b on a.TeamGuid = b.Code and b.ParentGuid is null\n" + " left join dbo.BAS_Material c on a.MaterialGuid = c.Guid\n" + " left join BAS_MatStdSort d on a.MatStdSortGuid = d.Guid\n" + " where a.ConfirmUser is null\n" + " and b.Guid = 1\n" + " order by a.ContractBillNO desc"; Assert.assertEquals("SELECT TOP 10 Guid, ProManager, WorkOrderType, Name, WorkNote, TeamName, ConstructionSite, IsMaterial, MaterialGuid, MaterialCode, MaterialName, MatStdSortName FROM (SELECT ROW_NUMBER() OVER (ORDER BY ROW_ALIAS_1 DESC) PAGE_ROW_NUMBER, Guid, ProManager, WorkOrderType, Name, WorkNote, TeamName, ConstructionSite, IsMaterial, MaterialGuid, MaterialCode, MaterialName, MatStdSortName FROM (SELECT a.Guid, ProManager, WorkOrderType, a.Name, WorkNote, b.Name TeamName, ConstructionSite, iif(a.MaterialGuid IS NULL, 0, 1) AS IsMaterial, a.MaterialGuid, c.Code AS MaterialCode, c.FullName MaterialName, d.FullName MatStdSortName, a.ContractBillNO AS ROW_ALIAS_1 FROM RMC_WorkOrder a LEFT JOIN dbo.SYS_OrgFrame b ON a.TeamGuid = b.Code AND b.ParentGuid IS NULL LEFT JOIN dbo.BAS_Material c ON a.MaterialGuid = c.Guid LEFT JOIN BAS_MatStdSort d ON a.MatStdSortGuid = d.Guid WHERE a.ConfirmUser IS NULL AND b.Guid = 1) AS PAGE_TABLE_ALIAS) AS PAGE_TABLE_ALIAS WHERE PAGE_ROW_NUMBER > 1 ORDER BY PAGE_ROW_NUMBER", sqlServer.convertToPageSql(originalSql, 1, 10)); } @Test public void testSql354() { String originalSql = "SELECT ISNULL(tb.a, '') from table tb"; Assert.assertEquals("SELECT TOP 10 ISNULL(tb.a, '') FROM (SELECT ROW_NUMBER() OVER (ORDER BY RAND()) PAGE_ROW_NUMBER, ISNULL(tb.a, '') FROM (SELECT ISNULL(tb.a, '') FROM table tb) AS PAGE_TABLE_ALIAS) AS PAGE_TABLE_ALIAS WHERE PAGE_ROW_NUMBER > 1 ORDER BY PAGE_ROW_NUMBER", sqlServer.convertToPageSql(originalSql, 1, 10)); } @Test public void testSql374() { String originalSql = "select * from table_a order by id"; Assert.assertEquals("SELECT TOP 10 * FROM (SELECT ROW_NUMBER() OVER (ORDER BY id) PAGE_ROW_NUMBER, * FROM (SELECT * FROM table_a) AS PAGE_TABLE_ALIAS) AS PAGE_TABLE_ALIAS WHERE PAGE_ROW_NUMBER > 1 ORDER BY PAGE_ROW_NUMBER", sqlServer.convertToPageSql(originalSql, 1, 10)); } @Test public void testSql345() { String originalSql = "Select CC.ClinicID, CC.CaseHistoryNum, CC.CaseHistoryID, CC.DoctorID, CC.ClientRegisterID\n" + "From Client CC With(Nolock)\n" + "Left Outer Join Register CR With(Nolock) On CC.ClientRegisterID = CR.ClientRegisterID\n" + "Where CC.ClientID = 14374"; ReplaceSql replaceSql = new RegexWithNolockReplaceSql(); String replace = replaceSql.replace(originalSql); String pageSql = sqlServer.convertToPageSql(replace, 1, 10); String result = replaceSql.restore(pageSql); Assert.assertEquals("SELECT TOP 10 ClinicID, CaseHistoryNum, CaseHistoryID, DoctorID, ClientRegisterID FROM (SELECT ROW_NUMBER() OVER (ORDER BY RAND()) PAGE_ROW_NUMBER, ClinicID, CaseHistoryNum, CaseHistoryID, DoctorID, ClientRegisterID FROM (SELECT CC.ClinicID, CC.CaseHistoryNum, CC.CaseHistoryID, CC.DoctorID, CC.ClientRegisterID FROM Client CC WITH(NOLOCK) LEFT OUTER JOIN Register CR WITH(NOLOCK) ON CC.ClientRegisterID = CR.ClientRegisterID WHERE CC.ClientID = 14374) AS PAGE_TABLE_ALIAS) AS PAGE_TABLE_ALIAS WHERE PAGE_ROW_NUMBER > 1 ORDER BY PAGE_ROW_NUMBER", result); } @Test public void testSql306() { String originalSql = "Select * FROM table1 t1 with(nolock)\n" + "left join table2 t2 with(nolock) on t1.id=t2.id\n" + "left join table3 t3 with(nolock) on t1.id=t3.id"; ReplaceSql replaceSql = new RegexWithNolockReplaceSql(); String replace = replaceSql.replace(originalSql); String pageSql = sqlServer.convertToPageSql(replace, 1, 10); String result = replaceSql.restore(pageSql); Assert.assertEquals("SELECT TOP 10 * FROM (SELECT ROW_NUMBER() OVER (ORDER BY RAND()) PAGE_ROW_NUMBER, * FROM (SELECT * FROM table1 t1 WITH(NOLOCK) LEFT JOIN table2 t2 WITH(NOLOCK) ON t1.id = t2.id LEFT JOIN table3 t3 WITH(NOLOCK) ON t1.id = t3.id) AS PAGE_TABLE_ALIAS) AS PAGE_TABLE_ALIAS WHERE PAGE_ROW_NUMBER > 1 ORDER BY PAGE_ROW_NUMBER", result); } @Test public void testSql66() { String originalSql = "SELECT *\n" + "FROM\n" + "forum_post_info a with(nolock)\n" + "LEFT JOIN forum_carcase_tags as b with(nolock) on a.id = b.carcase_id where b.tag_id = 127"; ReplaceSql replaceSql = new RegexWithNolockReplaceSql(); String replace = replaceSql.replace(originalSql); String pageSql = sqlServer.convertToPageSql(replace, 1, 10); String smartCountSql = countSqlParser.getSmartCountSql(replace); smartCountSql = replaceSql.restore(smartCountSql); Assert.assertEquals("SELECT count(0) FROM forum_post_info a WITH(NOLOCK) LEFT JOIN forum_carcase_tags AS b WITH(NOLOCK) ON a.id = b.carcase_id WHERE b.tag_id = 127", smartCountSql); String result = replaceSql.restore(pageSql); Assert.assertEquals("SELECT TOP 10 * FROM (SELECT ROW_NUMBER() OVER (ORDER BY RAND()) PAGE_ROW_NUMBER, * FROM (SELECT * FROM forum_post_info a WITH(NOLOCK) LEFT JOIN forum_carcase_tags AS b WITH(NOLOCK) ON a.id = b.carcase_id WHERE b.tag_id = 127) AS PAGE_TABLE_ALIAS) AS PAGE_TABLE_ALIAS WHERE PAGE_ROW_NUMBER > 1 ORDER BY PAGE_ROW_NUMBER", result); } @Test public void testSql398() { String originalSql = "Select AUS.ScheduleID, AUS.SystemID, AUS.ClinicID, AUS.DoctorID, AUS.ScheduleDate, \n" + "\tAUS.StartTime, AUS.EndTime, AUS.Status, AUS.BookBy, AUS.Note, AUS.Remark, AUS.SourceType, CM.CompanyName,\n" + "\tAU.UserName As DoctorName, AU.UserNumber As DoctorNumber, CC.CodeDesc As ClinicName, CD.Lat, CD.Lng,\n" + "\tCD.ContactTel, CD.Address, CR.ConsultationStatusID, CR.RegisterStatus,A1.CodeDesc as AreaLevel1, A2.CodeDesc as AreaLevel2\n" + "\tFrom ACM_User_Schedule AUS with(nolock)\n" + "\tLeft Join Client_Register CR with(nolock) On AUS.BookBy=CR.ClientID And CR.SourceType='F' And AUS.ClientRegisterNum=CR.ClientRegisterNum \n" + "\tInner Join ACM_User AU with(nolock) On AU.UserID = AUS.DoctorID \n" + "\tInner Join Code_Clinic CC with(nolock) On AUS.ClinicID=CC.CodeID\n" + "\tInner Join Clinic_Detail CD with(nolock) On CC.CodeID = CD.ClinicID\n" + "\tInner Join Code_Area A1 with(nolock) On CD.AreaLevel1ID=A1.CodeID\n" + "\tInner Join Code_Area A2 with(nolock) On CD.AreaLevel2ID=A2.CodeID\n" + "\tInner Join Company_Master CM with(nolock) On CC.SystemID = CM.SystemID\n" + "\tWhere BookBy=1"; ReplaceSql replaceSql = new RegexWithNolockReplaceSql(); String replace = replaceSql.replace(originalSql); String pageSql = sqlServer.convertToPageSql(replace, 1, 10); String smartCountSql = countSqlParser.getSmartCountSql(replace); smartCountSql = replaceSql.restore(smartCountSql); Assert.assertEquals("SELECT count(0) FROM ACM_User_Schedule AUS WITH(NOLOCK) LEFT JOIN Client_Register CR WITH(NOLOCK) ON AUS.BookBy = CR.ClientID AND CR.SourceType = 'F' AND AUS.ClientRegisterNum = CR.ClientRegisterNum INNER JOIN ACM_User AU WITH(NOLOCK) ON AU.UserID = AUS.DoctorID INNER JOIN Code_Clinic CC WITH(NOLOCK) ON AUS.ClinicID = CC.CodeID INNER JOIN Clinic_Detail CD WITH(NOLOCK) ON CC.CodeID = CD.ClinicID INNER JOIN Code_Area A1 WITH(NOLOCK) ON CD.AreaLevel1ID = A1.CodeID INNER JOIN Code_Area A2 WITH(NOLOCK) ON CD.AreaLevel2ID = A2.CodeID INNER JOIN Company_Master CM WITH(NOLOCK) ON CC.SystemID = CM.SystemID WHERE BookBy = 1", smartCountSql); String result = replaceSql.restore(pageSql); Assert.assertEquals("SELECT TOP 10 ScheduleID, SystemID, ClinicID, DoctorID, ScheduleDate, StartTime, EndTime, Status, BookBy, Note, Remark, SourceType, CompanyName, DoctorName, DoctorNumber, ClinicName, Lat, Lng, ContactTel, Address, ConsultationStatusID, RegisterStatus, AreaLevel1, AreaLevel2 FROM (SELECT ROW_NUMBER() OVER (ORDER BY RAND()) PAGE_ROW_NUMBER, ScheduleID, SystemID, ClinicID, DoctorID, ScheduleDate, StartTime, EndTime, Status, BookBy, Note, Remark, SourceType, CompanyName, DoctorName, DoctorNumber, ClinicName, Lat, Lng, ContactTel, Address, ConsultationStatusID, RegisterStatus, AreaLevel1, AreaLevel2 FROM (SELECT AUS.ScheduleID, AUS.SystemID, AUS.ClinicID, AUS.DoctorID, AUS.ScheduleDate, AUS.StartTime, AUS.EndTime, AUS.Status, AUS.BookBy, AUS.Note, AUS.Remark, AUS.SourceType, CM.CompanyName, AU.UserName AS DoctorName, AU.UserNumber AS DoctorNumber, CC.CodeDesc AS ClinicName, CD.Lat, CD.Lng, CD.ContactTel, CD.Address, CR.ConsultationStatusID, CR.RegisterStatus, A1.CodeDesc AS AreaLevel1, A2.CodeDesc AS AreaLevel2 FROM ACM_User_Schedule AUS WITH(NOLOCK) LEFT JOIN Client_Register CR WITH(NOLOCK) ON AUS.BookBy = CR.ClientID AND CR.SourceType = 'F' AND AUS.ClientRegisterNum = CR.ClientRegisterNum INNER JOIN ACM_User AU WITH(NOLOCK) ON AU.UserID = AUS.DoctorID INNER JOIN Code_Clinic CC WITH(NOLOCK) ON AUS.ClinicID = CC.CodeID INNER JOIN Clinic_Detail CD WITH(NOLOCK) ON CC.CodeID = CD.ClinicID INNER JOIN Code_Area A1 WITH(NOLOCK) ON CD.AreaLevel1ID = A1.CodeID INNER JOIN Code_Area A2 WITH(NOLOCK) ON CD.AreaLevel2ID = A2.CodeID INNER JOIN Company_Master CM WITH(NOLOCK) ON CC.SystemID = CM.SystemID WHERE BookBy = 1) AS PAGE_TABLE_ALIAS) AS PAGE_TABLE_ALIAS WHERE PAGE_ROW_NUMBER > 1 ORDER BY PAGE_ROW_NUMBER", result); } @Test public void testSqlServerSquareBrackets() { String originalSql = "SELECT [ID] AS [ComsnCountID] FROM B_ComsnCount;"; String pageSql = sqlServer.convertToPageSql(originalSql, 1, 20); Assert.assertEquals("SELECT TOP 20 [ComsnCountID] FROM (SELECT ROW_NUMBER() OVER (ORDER BY RAND()) PAGE_ROW_NUMBER, [ComsnCountID] FROM (SELECT [ID] AS [ComsnCountID] FROM B_ComsnCount) AS PAGE_TABLE_ALIAS) AS PAGE_TABLE_ALIAS WHERE PAGE_ROW_NUMBER > 1 ORDER BY PAGE_ROW_NUMBER", pageSql); } @Test public void testSqlServer768() { String originalSql = "SELECT column1, column2, column3 from table1 \n" + "UNION \n" + "SELECT column1, column2, column3 from table2 \n" + "UNION \n" + "SELECT column1, column2, column3 from table3 \n" + "ORDER BY column1, column2"; String pageSql = sqlServer.convertToPageSql(originalSql, 1, 20); Assert.assertEquals("SELECT TOP 20 column1, column2, column3 FROM (SELECT ROW_NUMBER() OVER (ORDER BY column1, column2) PAGE_ROW_NUMBER, column1, column2, column3 FROM (SELECT column1, column2, column3 FROM (SELECT column1, column2, column3 FROM table1 UNION SELECT column1, column2, column3 FROM table2 UNION SELECT column1, column2, column3 FROM table3) AS WRAP_OUTER_TABLE) AS PAGE_TABLE_ALIAS) AS PAGE_TABLE_ALIAS WHERE PAGE_ROW_NUMBER > 1 ORDER BY PAGE_ROW_NUMBER", pageSql); } } ================================================ FILE: src/test/java/com/github/pagehelper/sql/SqlTest.java ================================================ /* * The MIT License (MIT) * * Copyright (c) 2014-2023 abel533@gmail.com * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ package com.github.pagehelper.sql; import com.github.pagehelper.PageHelper; import com.github.pagehelper.parser.CountSqlParser; import com.github.pagehelper.parser.SqlParserUtil; import com.github.pagehelper.parser.defaults.DefaultCountSqlParser; import net.sf.jsqlparser.statement.Statement; import net.sf.jsqlparser.statement.select.Select; import org.junit.Assert; import org.junit.Test; /** * @author liuzh */ public class SqlTest { CountSqlParser countSqlParser = new DefaultCountSqlParser(); @Test public void testSqlParser() { Assert.assertEquals("WITH AA AS (SELECT 1 FROM A1), BB AS (SELECT 1 FROM B2), AB AS (SELECT * FROM AA UNION ALL SELECT * FROM BB) SELECT count(0) FROM AB", countSqlParser.getSmartCountSql("WITH AA AS (SELECT 1 FROM A1), BB AS (SELECT 1 FROM B2), AB AS (SELECT * FROM AA UNION ALL SELECT * FROM BB) SELECT * FROM AB")); Assert.assertEquals("WITH cr AS (SELECT UserRegionCode FROM person.UserRegion WHERE Name LIKE 'C%') SELECT count(0) FROM person.StateProvince WHERE UserRegionCode IN (SELECT * FROM cr)", countSqlParser.getSmartCountSql("with " + "cr as " + "( " + " select UserRegionCode from person.UserRegion where Name like 'C%' order by name" + ") " + " " + "select * from person.StateProvince where UserRegionCode in (select * from cr)")); Assert.assertEquals("WITH cr AS (SELECT aaz093 FROM aa10 WHERE aaa100 LIKE 'AAB05%') SELECT count(0) FROM (SELECT count(1) FROM aa10 WHERE aaz093 IN (SELECT * FROM cr)) table_count", countSqlParser.getSmartCountSql("with cr as " + " (select aaz093 from aa10 where aaa100 like 'AAB05%' order by aaz093 desc) " + "select count(1) from aa10 where aaz093 in (select * from cr)")); Assert.assertEquals("SELECT count(0) FROM ac02 a LEFT JOIN aa10 b ON b.aaa100 = 'AAC031' AND b.aaa102 = a.aac031", countSqlParser.getSmartCountSql("select a.aac001,a.aac030,b.aaa103 " + " from ac02 a " + " left join aa10 b " + " on b.aaa100 = 'AAC031' " + " and b.aaa102 = a.aac031 " + " order by a.aac001")); Assert.assertEquals("SELECT count(0) FROM (SELECT * FROM aa10 WHERE aaa100 LIKE 'AAB05%' UNION SELECT * FROM aa10 WHERE aaa100 = 'AAC031') table_count", countSqlParser.getSmartCountSql("select * from aa10 WHERE aaa100 LIKE 'AAB05%' " + "union " + "select * from aa10 where aaa100 = 'AAC031'")); Assert.assertEquals("SELECT count(0) FROM (SELECT * FROM aa10 WHERE aaa100 LIKE 'AAB05%' UNION SELECT * FROM aa10 WHERE aaa100 = 'AAC031')", countSqlParser.getSmartCountSql("select * from (select * from aa10 WHERE aaa100 LIKE 'AAB05%' " + "union " + "select * from aa10 where aaa100 = 'AAC031')")); Assert.assertEquals("SELECT count(0) FROM (SELECT so.id, so.address, so.area_code, so.area_id, so.del_flag, so.email, so.fax, so.grade, so.icon, so.master, so.name, so.parent_id, so.parent_ids, so.phone, so.remarks, so.type, so.zip_code FROM sys_organization so LEFT JOIN sys_user_organization suo ON (suo.org_id = so.id OR FIND_IN_SET(suo.org_id, so.parent_ids)) WHERE suo.user_id = ? GROUP BY so.id LIMIT ?) table_count", countSqlParser.getSmartCountSql("select so.id,so.address,so.area_code,so.area_id,so.del_flag,so.email,so.fax,so.grade,so.icon,so.master, so.name,so.parent_id,so.parent_ids,so.phone,so.remarks,so.type,so.zip_code from sys_organization so LEFT JOIN sys_user_organization suo ON (suo.org_id = so.id or FIND_IN_SET(suo.org_id,so.parent_ids)) where suo.user_id = ? group by so.id LIMIT ? ")); Assert.assertEquals("SELECT count(0) FROM xx1 LEFT JOIN xx2 ON xx1.id = xx2.user_id WHERE 1 = 1 AND xx1.`name` LIKE \"%ll%\" AND xx1.status = 1 AND (xx2.`type` = 1)", countSqlParser.getSmartCountSql("select xx,xx,xx from xx1 left join xx2 on xx1.id=xx2.user_id where 1=1 and xx1.`name` like \"%ll%\" and xx1.status = 1 and (xx2.`type` = 1) order by xx1.number asc")); } @Test public void testSqlParser11() { Assert.assertEquals("SELECT count(0) FROM (SELECT so.id, so.address, so.area_code, so.area_id, so.del_flag, so.email, so.fax, so.grade, so.icon, so.master, so.name, so.parent_id, so.parent_ids, so.phone, so.remarks, so.type, so.zip_code FROM sys_organization so LEFT JOIN sys_user_organization suo ON (suo.org_id = so.id OR FIND_IN_SET(suo.org_id, so.parent_ids)) WHERE suo.user_id = ? GROUP BY so.id LIMIT ?) table_count", countSqlParser.getSmartCountSql( "select so.id,so.address,so.area_code,so.area_id,so.del_flag,so.email," + "so.fax,so.grade,so.icon,so.master, so.name,so.parent_id,so.parent_ids," + "so.phone,so.remarks,so.type,so.zip_code " + "from sys_organization so " + "LEFT JOIN sys_user_organization suo ON (suo.org_id = so.id or FIND_IN_SET(suo.org_id,so.parent_ids)) " + "where suo.user_id = ? group by so.id LIMIT ? ")); Assert.assertEquals("SELECT count(0) FROM sys_organization so LEFT JOIN sys_user_organization suo ON (suo.org_id = so.id OR FIND_IN_SET(suo.org_id, so.parent_ids)) WHERE suo.user_id = ?", countSqlParser.getSmartCountSql( "select so.id,so.address,so.area_code,so.area_id,so.del_flag,so.email," + "so.fax,so.grade,so.icon,so.master, so.name,so.parent_id,so.parent_ids," + "so.phone,so.remarks,so.type,so.zip_code " + "from sys_organization so " + "LEFT JOIN sys_user_organization suo ON (suo.org_id = so.id or FIND_IN_SET(suo.org_id,so.parent_ids)) " + "where suo.user_id = ?")); } @Test public void testSqlParser2() { Assert.assertEquals("SELECT count(0) FROM (SELECT name, count(id) FROM user GROUP BY name) table_count", countSqlParser.getSmartCountSql("select name,count(id) from user group by name")); } @Test public void testSqlParser3() { Assert.assertEquals("select count(0) from ( \n" + "SELECT *\n" + " FROM vwdatasearch\n" + " WHERE ComId = ?\n" + " AND (\n" + " Title1 %% ?\n" + " )\n" + "\n" + " ) tmp_count", countSqlParser.getSmartCountSql("SELECT *\n" + " FROM vwdatasearch\n" + " WHERE ComId = ?\n" + " AND (\n" + " Title1 %% ?\n" + " )\n")); } @Test public void testSqlParser4() { String sql = countSqlParser.getSmartCountSql("/* test */select name,count(id) from user group by name"); Assert.assertEquals("/* test */SELECT count(0) FROM (SELECT name, count(id) FROM user GROUP BY name) table_count", sql); } @Test public void testWithNolock() { String sql = "SELECT * FROM A WITH(NOLOCK) INNER JOIN B WITH(NOLOCK) ON A.TypeId = B.Id"; sql = sql.replaceAll("((?i)\\s*(\\w?)\\s*with\\s*\\(nolock\\))", " $2_PAGEWITHNOLOCK"); //解析SQL Statement stmt = SqlParserUtil.parse(sql); Select select = (Select) stmt; sql = select.toString(); sql = sql.replaceAll("\\s*(\\w*?)_PAGEWITHNOLOCK", " $1 WITH(NOLOCK)"); Assert.assertEquals("SELECT * FROM A WITH(NOLOCK) INNER JOIN B WITH(NOLOCK) ON A.TypeId = B.Id", sql); } @Test public void testSql375() { Assert.assertEquals("SELECT count(0) FROM tbl", countSqlParser.getSmartCountSql("SELECT IF(score >= 60, 'pass', 'failed') FROM tbl")); } @Test public void testSql350() { Assert.assertEquals("select count(0) from ( \n" + "select a,b,c from tb_test having a not null\n" + " ) tmp_count", countSqlParser.getSmartCountSql("select a,b,c from tb_test having a not null")); } @Test public void testSql555() { Assert.assertEquals("SELECT count(0) FROM (SELECT (a.column1 + a.column2) AS popCount FROM peaf_staff AS a ORDER BY FIELD(a.`store_id`, ?, ?), popCount DESC) table_count", countSqlParser.getSmartCountSql("SELECT (a.column1+a.column2) as popCount FROM peaf_staff AS a ORDER BY FIELD(a.`store_id`, ?, ?), popCount DESC\n")); } @Test public void testSql606() { Assert.assertEquals("SELECT count(0) FROM (SELECT (SELECT COUNT(1) FROM test1 WHERE test1.id = test.test1_id) AS successCount, (SELECT COUNT(1) FROM test1) AS Total FROM test HAVING successCount = Total) table_count", countSqlParser.getSmartCountSql("select\n" + "(SELECT COUNT(1) FROM test1 WHERE test1.id = test.test1_id )as successCount ,\n" + "(SELECT COUNT(1) FROM test1 ) as Total\n" + "from test\n" + "Having successCount = Total")); } @Test public void testSql201() { Assert.assertEquals("SELECT count(0) FROM BASE_PARENT bp LEFT JOIN (BASE_STUDENT bs, BASE_PARENT_STUDENT bst) ON (bp.ID = bst.PARENT_ID AND bs.ID = bst.STUDENT_ID) WHERE 1 = 1", countSqlParser.getSmartCountSql("SELECT bp.ID, bp.NAME, bp.PHONE, bp.IDCODE, bp.CREDENTIALS_PIC, bp.ROLE, bs.ID child_id, bs.NAME child_name " + "FROM BASE_PARENT bp " + "LEFT JOIN (BASE_STUDENT bs ,BASE_PARENT_STUDENT bst) ON (bp.ID = bst.PARENT_ID AND bs.ID = bst.STUDENT_ID) " + "WHERE 1 = 1")); } @Test public void testSql545() { Assert.assertEquals("SELECT count(0) FROM user_info", countSqlParser.getSmartCountSql(" select * from user_info order by [ ]")); } @Test public void testKeepOrderBy() { try { PageHelper.startPage(1, 10).keepOrderBy(true); Assert.assertEquals("select count(0) from ( \n" + " select * from user_info order by name desc\n" + " ) tmp_count", countSqlParser.getSmartCountSql(" select * from user_info order by name desc")); } finally { PageHelper.clearPage(); } try { PageHelper.startPage(1, 10).keepSubSelectOrderBy(true); Assert.assertEquals("SELECT count(0) FROM (SELECT id, name FROM user_info ORDER BY name DESC) temp", countSqlParser.getSmartCountSql("select * from (select id, name from user_info order by name desc) temp order by id")); } finally { PageHelper.clearPage(); } } } ================================================ FILE: src/test/java/com/github/pagehelper/test/basic/ArgumentsMapTest.java ================================================ /* * The MIT License (MIT) * * Copyright (c) 2014-2023 abel533@gmail.com * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ package com.github.pagehelper.test.basic; import com.github.pagehelper.Page; import com.github.pagehelper.mapper.UserMapper; import com.github.pagehelper.model.User; import com.github.pagehelper.util.MybatisHelper; import org.apache.ibatis.session.SqlSession; import org.junit.Test; import java.util.List; import static org.junit.Assert.assertEquals; public class ArgumentsMapTest { /** * 使用Mapper接口调用时,使用PageHelper.startPage效果更好,不需要添加Mapper接口参数 */ @Test public void testArgumentsMap() { SqlSession sqlSession = MybatisHelper.getSqlSession(); UserMapper userMapper = sqlSession.getMapper(UserMapper.class); try { List list = userMapper.selectByPageNumSizeOrderBy(1, 10, "id desc"); assertEquals(10, list.size()); assertEquals(183, ((Page) list).getTotal()); list = userMapper.selectByPageNumSize(2, 10); assertEquals(10, list.size()); assertEquals(183, ((Page) list).getTotal()); list = userMapper.selectByPageNumSize(3, 20); assertEquals(20, list.size()); assertEquals(183, ((Page) list).getTotal()); } finally { sqlSession.close(); } } } ================================================ FILE: src/test/java/com/github/pagehelper/test/basic/ArgumentsObjTest.java ================================================ /* * The MIT License (MIT) * * Copyright (c) 2014-2023 abel533@gmail.com * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ package com.github.pagehelper.test.basic; import com.github.pagehelper.Page; import com.github.pagehelper.mapper.UserMapper; import com.github.pagehelper.model.User; import com.github.pagehelper.model.UserQueryModel; import com.github.pagehelper.util.MybatisHelper; import org.apache.ibatis.session.SqlSession; import org.junit.Test; import java.util.List; import static org.junit.Assert.assertEquals; public class ArgumentsObjTest { /** * 使用Mapper接口调用时,使用PageHelper.startPage效果更好,不需要添加Mapper接口参数 */ @Test public void testArgumentsObj() { SqlSession sqlSession = MybatisHelper.getSqlSession(); UserMapper userMapper = sqlSession.getMapper(UserMapper.class); try { UserQueryModel queryModel = new UserQueryModel(); queryModel.setPageNum(1); queryModel.setPageSize(10); queryModel.setOrderBy("id desc"); List list = userMapper.selectByQueryModel(queryModel); assertEquals(10, list.size()); assertEquals(183, ((Page) list).getTotal()); queryModel.setPageNum(2); queryModel.setOrderBy(null); list = userMapper.selectByQueryModel(queryModel); assertEquals(10, list.size()); assertEquals(183, ((Page) list).getTotal()); queryModel.setPageNum(3); queryModel.setPageSize(20); list = userMapper.selectByQueryModel(queryModel); assertEquals(20, list.size()); assertEquals(183, ((Page) list).getTotal()); } finally { sqlSession.close(); } } } ================================================ FILE: src/test/java/com/github/pagehelper/test/basic/AsyncCountTest.java ================================================ /* * The MIT License (MIT) * * Copyright (c) 2014-2023 abel533@gmail.com * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ package com.github.pagehelper.test.basic; import com.github.pagehelper.PageHelper; import com.github.pagehelper.dialect.auto.DataSourceAutoDialect; import com.github.pagehelper.dialect.auto.DataSourceNegotiationAutoDialect; import org.apache.ibatis.datasource.unpooled.UnpooledDataSource; import org.apache.ibatis.io.Resources; import org.apache.ibatis.session.SqlSession; import org.apache.ibatis.session.SqlSessionFactory; import org.apache.ibatis.session.SqlSessionFactoryBuilder; import org.junit.Ignore; import org.junit.Test; import java.io.IOException; import java.io.Reader; @Ignore public class AsyncCountTest { private static SqlSessionFactory sqlSessionFactory; static { try { //创建SqlSessionFactory Reader reader = Resources.getResourceAsReader("mybatis-config-async-count.xml"); sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader); reader.close(); } catch (IOException e) { } //添加一个针对 unpool 的 AutoDialect DataSourceNegotiationAutoDialect.registerAutoDialect(new DataSourceAutoDialect() { @Override public String getJdbcUrl(UnpooledDataSource unpooledDataSource) { return unpooledDataSource.getUrl(); } }); } /** * 获取Session * * @return */ public static SqlSession getSqlSession() { return sqlSessionFactory.openSession(); } /** * 使用命名空间调用时,使用PageHelper.startPage *

* startPage第三个参数可以控制是(true)否(false)执行count查询,使用两个查询的startPage时默认进行count查询 *

* 使用startPage方法时,如果同时使用RowBounds,以startPage为准 */ @Test public void testAsyncCount() { SqlSession sqlSession = getSqlSession(); long start = System.currentTimeMillis(); try { //获取第1页,10条内容,默认查询总数count PageHelper.startPage(1, 10).enableAsyncCount().keepOrderBy(true); sqlSession.selectList("selectEmployees"); System.out.println("异步耗时: " + (System.currentTimeMillis() - start)); } finally { sqlSession.close(); } sqlSession = getSqlSession(); start = System.currentTimeMillis(); try { //获取第1页,10条内容,默认查询总数count PageHelper.startPage(1, 10).keepOrderBy(true); sqlSession.selectList("selectEmployees"); System.out.println("同步耗时: " + (System.currentTimeMillis() - start)); } finally { sqlSession.close(); } } } ================================================ FILE: src/test/java/com/github/pagehelper/test/basic/CloseableTest.java ================================================ /* * The MIT License (MIT) * * Copyright (c) 2014-2023 abel533@gmail.com * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ package com.github.pagehelper.test.basic; import com.github.pagehelper.Page; import com.github.pagehelper.PageHelper; import com.github.pagehelper.mapper.UserMapper; import com.github.pagehelper.model.User; import com.github.pagehelper.util.MybatisHelper; import org.apache.ibatis.session.SqlSession; import org.junit.Assert; import org.junit.Test; import java.util.List; public class CloseableTest { @Test public void testCloseable() { SqlSession sqlSession = MybatisHelper.getSqlSession(); UserMapper userMapper = sqlSession.getMapper(UserMapper.class); //下面注释代码只能在jdk7+中进行测试 try (Page ignored = PageHelper.startPage(1, 10)) { int a = 10 / 0; userMapper.selectAll(); Assert.fail(); } catch (Exception e) { e.printStackTrace(); } //上面分页会被清理,这里不会被分页 List user = userMapper.selectAll(); Assert.assertEquals(183, user.size()); sqlSession.close(); } } ================================================ FILE: src/test/java/com/github/pagehelper/test/basic/CollectionMapTest.java ================================================ /* * The MIT License (MIT) * * Copyright (c) 2014-2023 abel533@gmail.com * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ package com.github.pagehelper.test.basic; import com.github.pagehelper.Page; import com.github.pagehelper.PageHelper; import com.github.pagehelper.mapper.UserMapper; import com.github.pagehelper.model.User; import com.github.pagehelper.util.MybatisHelper; import org.apache.ibatis.session.SqlSession; import org.junit.Test; import java.util.List; import static org.junit.Assert.assertEquals; public class CollectionMapTest { @Test public void test() { SqlSession sqlSession = MybatisHelper.getSqlSession(); UserMapper userMapper = sqlSession.getMapper(UserMapper.class); try { //获取第1页,10条内容,默认查询总数count PageHelper.startPage(1, 5); List list1 = userMapper.selectGreterThanId(1); //获取第1页,10条内容,默认查询总数count PageHelper.startPage(1, 5); List list2 = userMapper.selectCollectionMap(); assertEquals(5, list2.size()); assertEquals(183, ((Page) list2).getTotal()); } finally { sqlSession.close(); } } } ================================================ FILE: src/test/java/com/github/pagehelper/test/basic/CountColumnTest.java ================================================ /* * The MIT License (MIT) * * Copyright (c) 2014-2023 abel533@gmail.com * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ package com.github.pagehelper.test.basic; import com.github.pagehelper.Page; import com.github.pagehelper.PageHelper; import com.github.pagehelper.mapper.UserMapper; import com.github.pagehelper.model.User; import com.github.pagehelper.util.MybatisHelper; import org.apache.ibatis.session.SqlSession; import org.junit.Test; import java.util.List; import static org.junit.Assert.assertEquals; public class CountColumnTest { @Test public void testMapperWithStartPage() { SqlSession sqlSession = MybatisHelper.getSqlSession(); UserMapper userMapper = sqlSession.getMapper(UserMapper.class); try { //获取第1页,10条内容,默认查询总数count PageHelper.startPage(1, 10).countColumn("id"); User user = new User(); user.setName("刘"); List list = userMapper.selectLike(user); assertEquals(78, list.get(0).getId()); assertEquals(10, list.size()); assertEquals(15, ((Page) list).getTotal()); //获取第1页,10条内容,默认查询总数count PageHelper.startPage(2, 10); list = userMapper.selectLike(user); assertEquals(88, list.get(0).getId()); assertEquals(5, list.size()); assertEquals(15, ((Page) list).getTotal()); } finally { sqlSession.close(); } } @Test(expected = Exception.class) public void testCountColumnInject() { SqlSession sqlSession = MybatisHelper.getSqlSession(); try { //获取第1页,10条内容,默认查询总数count PageHelper.startPage(1, 10).countColumn("delete from user"); } finally { sqlSession.close(); } } } ================================================ FILE: src/test/java/com/github/pagehelper/test/basic/EnumTest.java ================================================ /* * The MIT License (MIT) * * Copyright (c) 2014-2023 abel533@gmail.com * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ package com.github.pagehelper.test.basic; import com.github.pagehelper.PageHelper; import com.github.pagehelper.mapper.UserMapper; import com.github.pagehelper.model.Code; import com.github.pagehelper.model.UserCode; import com.github.pagehelper.util.MybatisHelper; import org.apache.ibatis.session.SqlSession; import org.junit.Assert; import org.junit.Test; import java.util.List; public class EnumTest { @Test public void testCloseable() { SqlSession sqlSession = MybatisHelper.getSqlSession(); UserMapper userMapper = sqlSession.getMapper(UserMapper.class); PageHelper.startPage(1, 2); List userCodes = userMapper.selectByCode(Code.LR); Assert.assertEquals(1, userCodes.size()); sqlSession.close(); } } ================================================ FILE: src/test/java/com/github/pagehelper/test/basic/IPageTest.java ================================================ /* * The MIT License (MIT) * * Copyright (c) 2014-2023 abel533@gmail.com * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ package com.github.pagehelper.test.basic; import com.github.pagehelper.IPage; import com.github.pagehelper.Page; import com.github.pagehelper.mapper.UserMapper; import com.github.pagehelper.model.User; import com.github.pagehelper.model.UserQueryModel; import com.github.pagehelper.util.MybatisHelper; import org.apache.ibatis.session.SqlSession; import org.junit.Test; import java.util.List; import static org.junit.Assert.assertEquals; public class IPageTest { @Test public void testIPage() { SqlSession sqlSession = MybatisHelper.getSqlSession(); UserMapper userMapper = sqlSession.getMapper(UserMapper.class); try { UserIPage queryModel = new UserIPage(); queryModel.setPageNum(1); queryModel.setPageSize(10); queryModel.setOrderBy("id desc"); List list = userMapper.selectByQueryModel(queryModel); assertEquals(10, list.size()); assertEquals(183, ((Page) list).getTotal()); queryModel.setPageNum(2); queryModel.setOrderBy(null); list = userMapper.selectByQueryModel(queryModel); assertEquals(10, list.size()); assertEquals(183, ((Page) list).getTotal()); queryModel.setPageNum(null); queryModel.setPageSize(null); queryModel.setOrderBy("id asc"); list = userMapper.selectByQueryModel(queryModel); assertEquals(1, list.get(0).getId()); assertEquals(183, list.size()); assertEquals(183, ((Page) list).getTotal()); } finally { sqlSession.close(); } } public static class UserIPage extends UserQueryModel implements IPage { } } ================================================ FILE: src/test/java/com/github/pagehelper/test/basic/OffsetTest.java ================================================ /* * The MIT License (MIT) * * Copyright (c) 2014-2023 abel533@gmail.com * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ package com.github.pagehelper.test.basic; import com.github.pagehelper.Page; import com.github.pagehelper.PageHelper; import com.github.pagehelper.PageInfo; import com.github.pagehelper.mapper.UserMapper; import com.github.pagehelper.model.User; import com.github.pagehelper.util.MybatisHelper; import org.apache.ibatis.session.SqlSession; import org.junit.Test; import java.util.List; import static org.junit.Assert.assertEquals; public class OffsetTest { @Test public void testOffset() { SqlSession sqlSession = MybatisHelper.getSqlSession(); UserMapper userMapper = sqlSession.getMapper(UserMapper.class); try { PageHelper.startPage(1, 6); List list = userMapper.selectAll(); assertEquals(6, list.size()); assertEquals(183, ((Page) list).getTotal()); PageHelper.offsetPage(6, 20); list = userMapper.selectAll(); PageInfo pageInfo = new PageInfo(list); System.out.println(pageInfo.toString()); assertEquals(2, ((Page) list).getPageNum()); assertEquals(20, list.size()); assertEquals(183, ((Page) list).getTotal()); PageHelper.offsetPage(1, 180); list = userMapper.selectAll(); pageInfo = new PageInfo(list); System.out.println(pageInfo.toString()); assertEquals(2, ((Page) list).getPageNum()); assertEquals(180, list.size()); assertEquals(183, ((Page) list).getTotal()); PageHelper.offsetPage(0, Integer.MAX_VALUE); list = userMapper.selectAll(); pageInfo = new PageInfo(list); System.out.println(pageInfo.toString()); assertEquals(1, ((Page) list).getPageNum()); assertEquals(183, list.size()); assertEquals(183, ((Page) list).getTotal()); } finally { sqlSession.close(); } } @Test public void testPageNum() { SqlSession sqlSession = MybatisHelper.getSqlSession(); UserMapper userMapper = sqlSession.getMapper(UserMapper.class); try { PageHelper.offsetPage(5, 5); List list = userMapper.selectAll(); assertEquals(2, ((Page) list).getPageNum()); assertEquals(5, list.size()); assertEquals(183, ((Page) list).getTotal()); PageHelper.offsetPage(15, 5); list = userMapper.selectAll(); assertEquals(4, ((Page) list).getPageNum()); assertEquals(5, list.size()); assertEquals(183, ((Page) list).getTotal()); } finally { sqlSession.close(); } } } ================================================ FILE: src/test/java/com/github/pagehelper/test/basic/PageHelperTest.java ================================================ /* * The MIT License (MIT) * * Copyright (c) 2014-2023 abel533@gmail.com * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ package com.github.pagehelper.test.basic; import com.github.pagehelper.Page; import com.github.pagehelper.PageHelper; import com.github.pagehelper.PageParam; import com.github.pagehelper.mapper.UserMapper; import com.github.pagehelper.model.User; import com.github.pagehelper.util.MybatisHelper; import org.apache.ibatis.session.RowBounds; import org.apache.ibatis.session.SqlSession; import org.junit.Test; import java.util.List; import static org.junit.Assert.assertEquals; public class PageHelperTest { @Test public void shouldGetAllCountries() { SqlSession sqlSession = MybatisHelper.getSqlSession(); try { List list = sqlSession.selectList("selectAll"); assertEquals(183, list.size()); } finally { sqlSession.close(); } } /** * 使用Mapper接口调用时,对接口增加RowBounds参数,不需要修改对应的xml配置(或注解配置) *

* RowBounds方式不进行count查询,可以通过修改Page代码实现 *

* 这种情况下如果同时使用startPage方法,以startPage为准 */ @Test public void testMapperWithRowBounds() { SqlSession sqlSession = MybatisHelper.getSqlSession(); UserMapper userMapper = sqlSession.getMapper(UserMapper.class); try { //获取第1页,10条内容,默认查询总数count List list = userMapper.selectAll(new RowBounds(0, 10)); assertEquals(10, list.size()); assertEquals(183, ((Page) list).getTotal()); //判断查询结果的位置是否正确 assertEquals(1, list.get(0).getId()); assertEquals(10, list.get(list.size() - 1).getId()); //获取第2页,10条内容,显式查询总数count list = userMapper.selectAll(new RowBounds(10, 10)); assertEquals(10, list.size()); assertEquals(183, ((Page) list).getTotal()); //判断查询结果的位置是否正确 assertEquals(11, list.get(0).getId()); assertEquals(20, list.get(list.size() - 1).getId()); //获取第3页,20条内容,默认查询总数count list = userMapper.selectAll(new RowBounds(60, 20)); assertEquals(20, list.size()); assertEquals(183, ((Page) list).getTotal()); //判断查询结果的位置是否正确 assertEquals(61, list.get(0).getId()); assertEquals(80, list.get(list.size() - 1).getId()); //同时使用startPage和RowBounds时,以startPage为准 PageHelper.startPage(1, 20); list = userMapper.selectAll(new RowBounds(60, 20)); assertEquals(20, list.size()); assertEquals(183, ((Page) list).getTotal()); //判断查询结果的位置是否正确 assertEquals(1, list.get(0).getId()); assertEquals(20, list.get(list.size() - 1).getId()); } finally { sqlSession.close(); } } /** * 使用命名空间调用时,使用PageHelper.startPage *

* startPage第三个参数可以控制是(true)否(false)执行count查询,使用两个查询的startPage时默认进行count查询 *

* 使用startPage方法时,如果同时使用RowBounds,以startPage为准 */ @Test public void testNamespaceWithStartPage() { SqlSession sqlSession = MybatisHelper.getSqlSession(); try { //获取第1页,10条内容,默认查询总数count PageHelper.startPage(1, 10); List list = sqlSession.selectList("selectAll"); assertEquals(10, list.size()); assertEquals(183, ((Page) list).getTotal()); //获取第2页,10条内容,显式查询总数count PageHelper.startPage(2, 10, true); list = sqlSession.selectList("selectAll"); assertEquals(10, list.size()); assertEquals(183, ((Page) list).getTotal()); //获取第2页,10条内容,不查询总数count PageHelper.startPage(2, 10, false); list = sqlSession.selectList("selectAll"); assertEquals(10, list.size()); assertEquals(-1, ((Page) list).getTotal()); //获取第3页,20条内容,默认查询总数count PageHelper.startPage(3, 20); list = sqlSession.selectList("selectAll"); assertEquals(20, list.size()); assertEquals(183, ((Page) list).getTotal()); //获取第3页,20条内容,默认查询总数count PageHelper.startPage(new PageParam(4, 20)); list = sqlSession.selectList("selectAll"); assertEquals(20, list.size()); assertEquals(183, ((Page) list).getTotal()); } finally { sqlSession.close(); } } /** * 使用命名空间方式的RowBounds进行分页,使用RowBounds时不进行count查询 * 通过修改代码可以进行count查询,没法通过其他方法改变参数 * 因为如果通过调用一个别的方法来标记count查询,还不如直接startPage *

* 同时使用startPage时,以startPage为准,会根据startPage参数来查询 */ @Test public void testNamespaceWithRowBounds() { SqlSession sqlSession = MybatisHelper.getSqlSession(); try { //获取从0开始,10条内容 List list = sqlSession.selectList("selectAll", null, new RowBounds(0, 10)); assertEquals(10, list.size()); assertEquals(183, ((Page) list).getTotal()); //判断查询结果的位置是否正确 assertEquals(1, list.get(0).getId()); assertEquals(10, list.get(list.size() - 1).getId()); //获取从10开始,10条内容 list = sqlSession.selectList("selectAll", null, new RowBounds(10, 10)); assertEquals(10, list.size()); assertEquals(183, ((Page) list).getTotal()); //判断查询结果的位置是否正确 assertEquals(11, list.get(0).getId()); assertEquals(20, list.get(list.size() - 1).getId()); //获取从20开始,20条内容 list = sqlSession.selectList("selectAll", null, new RowBounds(20, 20)); assertEquals(20, list.size()); assertEquals(183, ((Page) list).getTotal()); //判断查询结果的位置是否正确 assertEquals(21, list.get(0).getId()); assertEquals(40, list.get(list.size() - 1).getId()); //同时使用startPage和RowBounds时,以startPage为准 PageHelper.startPage(1, 20); list = sqlSession.selectList("selectAll", null, new RowBounds(0, 10)); assertEquals(20, list.size()); assertEquals(183, ((Page) list).getTotal()); //判断查询结果的位置是否正确 assertEquals(1, list.get(0).getId()); assertEquals(20, list.get(list.size() - 1).getId()); } finally { sqlSession.close(); } } } ================================================ FILE: src/test/java/com/github/pagehelper/test/basic/PageInfoTest.java ================================================ /* * The MIT License (MIT) * * Copyright (c) 2014-2023 abel533@gmail.com * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ package com.github.pagehelper.test.basic; import com.github.pagehelper.PageHelper; import com.github.pagehelper.PageInfo; import com.github.pagehelper.PageSerializable; import com.github.pagehelper.mapper.UserMapper; import com.github.pagehelper.model.User; import com.github.pagehelper.util.MybatisHelper; import org.apache.ibatis.session.SqlSession; import org.junit.Test; import java.util.List; import static org.junit.Assert.assertEquals; public class PageInfoTest { /** * 使用Mapper接口调用时,使用PageHelper.startPage效果更好,不需要添加Mapper接口参数 */ @Test public void testPageSize10() { SqlSession sqlSession = MybatisHelper.getSqlSession(); UserMapper userMapper = sqlSession.getMapper(UserMapper.class); try { //获取第1页,10条内容,默认查询总数count PageHelper.startPage(1, 10); List list = userMapper.selectAll(); System.out.println(list); PageInfo page = new PageInfo(list); assertEquals(1, page.getPageNum()); assertEquals(10, page.getPageSize()); assertEquals(1, page.getStartRow()); assertEquals(10, page.getEndRow()); assertEquals(183, page.getTotal()); assertEquals(19, page.getPages()); assertEquals(true, page.isIsFirstPage()); assertEquals(false, page.isIsLastPage()); assertEquals(false, page.isHasPreviousPage()); assertEquals(true, page.isHasNextPage()); PageSerializable serializable = PageSerializable.of(list); assertEquals(183, serializable.getTotal()); //获取第2页,10条内容,默认查询总数count PageHelper.startPage(2, 10); list = userMapper.selectAll(); page = new PageInfo(list); assertEquals(2, page.getPageNum()); assertEquals(10, page.getPageSize()); assertEquals(11, page.getStartRow()); assertEquals(20, page.getEndRow()); assertEquals(183, page.getTotal()); assertEquals(19, page.getPages()); assertEquals(false, page.isIsFirstPage()); assertEquals(false, page.isIsLastPage()); assertEquals(true, page.isHasPreviousPage()); assertEquals(true, page.isHasNextPage()); //获取第19页,10条内容,默认查询总数count PageHelper.startPage(19, 10); list = userMapper.selectAll(); page = new PageInfo(list); assertEquals(19, page.getPageNum()); assertEquals(10, page.getPageSize()); assertEquals(181, page.getStartRow()); assertEquals(183, page.getEndRow()); assertEquals(183, page.getTotal()); assertEquals(19, page.getPages()); assertEquals(false, page.isIsFirstPage()); assertEquals(true, page.isIsLastPage()); assertEquals(true, page.isHasPreviousPage()); assertEquals(false, page.isHasNextPage()); } finally { sqlSession.close(); } } /** * 使用Mapper接口调用时,使用PageHelper.startPage效果更好,不需要添加Mapper接口参数 */ @Test public void testPageSize50() { SqlSession sqlSession = MybatisHelper.getSqlSession(); UserMapper userMapper = sqlSession.getMapper(UserMapper.class); try { //获取第1页,50条内容,默认查询总数count PageHelper.startPage(1, 50); List list = userMapper.selectAll(); PageInfo page = new PageInfo(list); assertEquals(1, page.getPageNum()); assertEquals(50, page.getPageSize()); assertEquals(1, page.getStartRow()); assertEquals(50, page.getEndRow()); assertEquals(183, page.getTotal()); assertEquals(4, page.getPages()); assertEquals(true, page.isIsFirstPage()); assertEquals(false, page.isIsLastPage()); assertEquals(false, page.isHasPreviousPage()); assertEquals(true, page.isHasNextPage()); //获取第2页,50条内容,默认查询总数count PageHelper.startPage(2, 50); list = userMapper.selectAll(); page = new PageInfo(list); assertEquals(2, page.getPageNum()); assertEquals(50, page.getPageSize()); assertEquals(51, page.getStartRow()); assertEquals(100, page.getEndRow()); assertEquals(183, page.getTotal()); assertEquals(4, page.getPages()); assertEquals(false, page.isIsFirstPage()); assertEquals(false, page.isIsLastPage()); assertEquals(true, page.isHasPreviousPage()); assertEquals(true, page.isHasNextPage()); //获取第3页,50条内容,默认查询总数count PageHelper.startPage(3, 50); list = userMapper.selectAll(); page = new PageInfo(list); assertEquals(3, page.getPageNum()); assertEquals(50, page.getPageSize()); assertEquals(101, page.getStartRow()); assertEquals(150, page.getEndRow()); assertEquals(183, page.getTotal()); assertEquals(4, page.getPages()); assertEquals(false, page.isIsFirstPage()); assertEquals(false, page.isIsLastPage()); assertEquals(true, page.isHasPreviousPage()); assertEquals(true, page.isHasNextPage()); //获取第4页,50条内容,默认查询总数count PageHelper.startPage(4, 50); list = userMapper.selectAll(); page = new PageInfo(list); assertEquals(4, page.getPageNum()); assertEquals(50, page.getPageSize()); assertEquals(151, page.getStartRow()); assertEquals(183, page.getEndRow()); assertEquals(183, page.getTotal()); assertEquals(4, page.getPages()); assertEquals(false, page.isIsFirstPage()); assertEquals(true, page.isIsLastPage()); assertEquals(true, page.isHasPreviousPage()); assertEquals(false, page.isHasNextPage()); } finally { sqlSession.close(); } } /** * 使用Mapper接口调用时,使用PageHelper.startPage效果更好,不需要添加Mapper接口参数 */ @Test public void testNavigatePages() { SqlSession sqlSession = MybatisHelper.getSqlSession(); UserMapper userMapper = sqlSession.getMapper(UserMapper.class); try { //获取第1页,10条内容,默认查询总数count PageHelper.startPage(1, 10); List list = userMapper.selectAll(); PageInfo page = new PageInfo(list, 20); assertEquals(1, page.getPageNum()); assertEquals(10, page.getPageSize()); assertEquals(1, page.getStartRow()); assertEquals(10, page.getEndRow()); assertEquals(183, page.getTotal()); assertEquals(19, page.getPages()); assertEquals(true, page.isIsFirstPage()); assertEquals(false, page.isIsLastPage()); assertEquals(false, page.isHasPreviousPage()); assertEquals(true, page.isHasNextPage()); //获取第2页,50条内容,默认查询总数count PageHelper.startPage(2, 50); list = userMapper.selectAll(); page = new PageInfo(list, 2); assertEquals(2, page.getPageNum()); assertEquals(50, page.getPageSize()); assertEquals(51, page.getStartRow()); assertEquals(100, page.getEndRow()); assertEquals(183, page.getTotal()); assertEquals(4, page.getPages()); assertEquals(false, page.isIsFirstPage()); assertEquals(false, page.isIsLastPage()); assertEquals(true, page.isHasPreviousPage()); assertEquals(true, page.isHasNextPage()); } finally { sqlSession.close(); } } /** * 手动指定记录总数,返回分页信息 */ @Test public void testPageInfoOfTotal() { SqlSession sqlSession = MybatisHelper.getSqlSession(); UserMapper userMapper = sqlSession.getMapper(UserMapper.class); try { //获取第1页,10条内容,关闭查询总数 PageHelper.startPage(1, 10, false); List list = userMapper.selectAll(); System.out.println(list); //手动指定总数 PageInfo page = PageInfo.of(183L, list); assertEquals(1, page.getPageNum()); assertEquals(10, page.getPageSize()); assertEquals(1, page.getStartRow()); assertEquals(10, page.getEndRow()); assertEquals(183, page.getTotal()); assertEquals(19, page.getPages()); assertEquals(true, page.isIsFirstPage()); assertEquals(false, page.isIsLastPage()); assertEquals(false, page.isHasPreviousPage()); assertEquals(true, page.isHasNextPage()); PageSerializable serializable = PageSerializable.of(list); assertEquals(183, serializable.getTotal()); //获取第2页,10条内容,关闭查询总数 PageHelper.startPage(2, 10, false); list = userMapper.selectAll(); //手动指定总数 page = PageInfo.of(183L, list); assertEquals(2, page.getPageNum()); assertEquals(10, page.getPageSize()); assertEquals(11, page.getStartRow()); assertEquals(20, page.getEndRow()); assertEquals(183, page.getTotal()); assertEquals(19, page.getPages()); assertEquals(false, page.isIsFirstPage()); assertEquals(false, page.isIsLastPage()); assertEquals(true, page.isHasPreviousPage()); assertEquals(true, page.isHasNextPage()); //获取第19页,10条内容,关闭查询总数 PageHelper.startPage(19, 10, false); list = userMapper.selectAll(); //手动指定总数 page = PageInfo.of(183L, list); assertEquals(19, page.getPageNum()); assertEquals(10, page.getPageSize()); assertEquals(181, page.getStartRow()); assertEquals(183, page.getEndRow()); assertEquals(183, page.getTotal()); assertEquals(19, page.getPages()); assertEquals(false, page.isIsFirstPage()); assertEquals(true, page.isIsLastPage()); assertEquals(true, page.isHasPreviousPage()); assertEquals(false, page.isHasNextPage()); //不使用PageHelper.startPage list = userMapper.selectAll(); //手动指定总数 page = PageInfo.of(183L, list); assertEquals(1, page.getPageNum()); assertEquals(183, page.getPageSize()); assertEquals(0, page.getStartRow()); assertEquals(182, page.getEndRow()); assertEquals(183, page.getTotal()); assertEquals(1, page.getPages()); assertEquals(true, page.isIsFirstPage()); assertEquals(true, page.isIsLastPage()); assertEquals(false, page.isHasPreviousPage()); assertEquals(false, page.isHasNextPage()); } finally { sqlSession.close(); } } } ================================================ FILE: src/test/java/com/github/pagehelper/test/basic/RemoveOrderTest.java ================================================ /* * The MIT License (MIT) * * Copyright (c) 2014-2023 abel533@gmail.com * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ package com.github.pagehelper.test.basic; import com.github.pagehelper.Page; import com.github.pagehelper.PageHelper; import com.github.pagehelper.mapper.UserMapper; import com.github.pagehelper.model.User; import com.github.pagehelper.util.MybatisHelper; import org.apache.ibatis.session.SqlSession; import org.junit.Assert; import org.junit.Test; import java.util.List; /** * Created by Administrator on 14-8-24. */ public class RemoveOrderTest { @Test public void simpleOrderTest() { SqlSession sqlSession = MybatisHelper.getSqlSession(); UserMapper userMapper = sqlSession.getMapper(UserMapper.class); //主要观看查询执行count查询的sql try { PageHelper.startPage(1, 50); List list = userMapper.selectAllOrderby(); //总数183 Assert.assertEquals(183, ((Page) list).getTotal()); } finally { sqlSession.close(); } } @Test public void paramsOrderTest() { SqlSession sqlSession = MybatisHelper.getSqlSession(); UserMapper userMapper = sqlSession.getMapper(UserMapper.class); //主要观看查询执行count查询的sql try { PageHelper.startPage(1, 50); List list = userMapper.selectAllOrderByParams("name", "py"); //总数183 Assert.assertEquals(183, ((Page) list).getTotal()); } finally { sqlSession.close(); } } } ================================================ FILE: src/test/java/com/github/pagehelper/test/basic/TestDistinct.java ================================================ /* * The MIT License (MIT) * * Copyright (c) 2014-2023 abel533@gmail.com * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ package com.github.pagehelper.test.basic; import com.github.pagehelper.Page; import com.github.pagehelper.PageHelper; import com.github.pagehelper.mapper.UserMapper; import com.github.pagehelper.model.User; import com.github.pagehelper.util.MybatisHelper; import org.apache.ibatis.session.SqlSession; import org.junit.Test; import java.util.List; import static org.junit.Assert.assertEquals; public class TestDistinct { @Test public void test() { SqlSession sqlSession = MybatisHelper.getSqlSession(); UserMapper userMapper = sqlSession.getMapper(UserMapper.class); try { //获取第1页,10条内容,默认查询总数count PageHelper.startPage(1, 10); List list = userMapper.selectDistinct(); assertEquals(10, list.size()); assertEquals(58, ((Page) list).getTotal()); } finally { sqlSession.close(); } } } ================================================ FILE: src/test/java/com/github/pagehelper/test/basic/TestExecute.java ================================================ /* * The MIT License (MIT) * * Copyright (c) 2014-2023 abel533@gmail.com * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ package com.github.pagehelper.test.basic; import com.github.pagehelper.PageHelper; import com.github.pagehelper.mapper.UserMapper; import com.github.pagehelper.model.User; import com.github.pagehelper.util.MybatisHelper; import org.apache.ibatis.session.SqlSession; import org.junit.Assert; import org.junit.Test; import java.util.List; import java.util.Map; public class TestExecute { @Test public void test() { SqlSession sqlSession = MybatisHelper.getSqlSession(); UserMapper userMapper = sqlSession.getMapper(UserMapper.class); try { //获取第1页,10条内容,默认查询总数count PageHelper.startPage(1, 10); List> mapList = userMapper.execute("select * from user"); Assert.assertEquals(10, mapList.size()); mapList = userMapper.execute("select * from user"); Assert.assertEquals(183, mapList.size()); List userList = userMapper.selectAll(); Assert.assertEquals(183, userList.size()); } finally { sqlSession.close(); } } } ================================================ FILE: src/test/java/com/github/pagehelper/test/basic/TestISelect.java ================================================ /* * The MIT License (MIT) * * Copyright (c) 2014-2023 abel533@gmail.com * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ package com.github.pagehelper.test.basic; import com.github.pagehelper.ISelect; import com.github.pagehelper.Page; import com.github.pagehelper.PageHelper; import com.github.pagehelper.PageInfo; import com.github.pagehelper.mapper.UserMapper; import com.github.pagehelper.model.User; import com.github.pagehelper.util.MybatisHelper; import org.apache.ibatis.session.SqlSession; import org.junit.Test; import static org.junit.Assert.assertEquals; /** * @author liuzh_3nofxnp * @since 2015-12-26 09:15 */ public class TestISelect { @Test public void testGroupBy2() { SqlSession sqlSession = MybatisHelper.getSqlSession(); final UserMapper userMapper = sqlSession.getMapper(UserMapper.class); try { Page page = PageHelper.startPage(1, 10).doSelectPage(new ISelect() { @Override public void doSelect() { userMapper.selectGroupBy(); } }); //下面是该方法的lambda用法 //Page page = PageHelper.startPage(1, 10).setOrderBy("id desc").doSelectPage(()-> userMapper.selectGroupBy()); //1,'Angola','AO' assertEquals(1, page.get(0).getId()); assertEquals(10, page.size()); assertEquals(183, page.getTotal()); PageInfo pageInfo = page.toPageInfo(); System.out.println(pageInfo); pageInfo = PageHelper.startPage(1, 10).doSelectPageInfo(new ISelect() { @Override public void doSelect() { userMapper.selectGroupBy(); } }); //lambda //pageInfo = PageHelper.startPage(1, 10).setOrderBy("id desc").doSelectPageInfo(() -> userMapper.selectGroupBy()); System.out.println(pageInfo); final User user = new User(); user.setName("c"); long total = PageHelper.count(new ISelect() { @Override public void doSelect() { userMapper.selectLike(user); } }); //lambda //long total = PageHelper.count(()->userMapper.selectLike(user)); System.out.println(total); } finally { sqlSession.close(); } } } ================================================ FILE: src/test/java/com/github/pagehelper/test/basic/TestIntMax.java ================================================ /* * The MIT License (MIT) * * Copyright (c) 2014-2023 abel533@gmail.com * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ package com.github.pagehelper.test.basic; import com.github.pagehelper.Page; import com.github.pagehelper.PageHelper; import com.github.pagehelper.mapper.UserMapper; import com.github.pagehelper.model.User; import com.github.pagehelper.util.MybatisHelper; import org.apache.ibatis.session.SqlSession; import org.junit.Test; import java.util.List; import static org.junit.Assert.assertEquals; public class TestIntMax { /** * 使用Mapper接口调用时,使用PageHelper.startPage效果更好,不需要添加Mapper接口参数 */ @Test public void testCountCache() { SqlSession sqlSession = MybatisHelper.getSqlSession(); UserMapper userMapper = sqlSession.getMapper(UserMapper.class); try { //获取第1页,10条内容,默认查询总数count PageHelper.startPage(1, Integer.MAX_VALUE); List list = userMapper.selectIf(1); assertEquals(2, list.get(0).getId()); assertEquals(182, list.size()); assertEquals(182, ((Page) list).getTotal()); //获取第1页,10条内容,默认查询总数count PageHelper.startPage(1, Integer.MAX_VALUE); list = userMapper.selectIf(null); assertEquals(1, list.get(0).getId()); assertEquals(183, list.size()); assertEquals(183, ((Page) list).getTotal()); } finally { sqlSession.close(); } } } ================================================ FILE: src/test/java/com/github/pagehelper/test/basic/TestLike.java ================================================ /* * The MIT License (MIT) * * Copyright (c) 2014-2023 abel533@gmail.com * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ package com.github.pagehelper.test.basic; import com.github.pagehelper.Page; import com.github.pagehelper.PageHelper; import com.github.pagehelper.mapper.UserMapper; import com.github.pagehelper.model.User; import com.github.pagehelper.util.MybatisHelper; import org.apache.ibatis.session.SqlSession; import org.junit.Test; import java.util.List; import static org.junit.Assert.assertEquals; public class TestLike { /** * 使用Mapper接口调用时,使用PageHelper.startPage效果更好,不需要添加Mapper接口参数 */ @Test public void testMapperWithStartPage() { SqlSession sqlSession = MybatisHelper.getSqlSession(); UserMapper userMapper = sqlSession.getMapper(UserMapper.class); try { //获取第1页,10条内容,默认查询总数count PageHelper.startPage(1, 10); User user = new User(); user.setName("刘"); List list = userMapper.selectLike(user); assertEquals(78, list.get(0).getId()); assertEquals(10, list.size()); assertEquals(15, ((Page) list).getTotal()); //获取第1页,10条内容,默认查询总数count PageHelper.startPage(2, 10); list = userMapper.selectLike(user); assertEquals(88, list.get(0).getId()); assertEquals(5, list.size()); assertEquals(15, ((Page) list).getTotal()); } finally { sqlSession.close(); } } /** * 使用Mapper接口调用时,使用PageHelper.startPage效果更好,不需要添加Mapper接口参数 */ @Test public void testMapperWithStartPage_OrderBy() { SqlSession sqlSession = MybatisHelper.getSqlSession(); UserMapper userMapper = sqlSession.getMapper(UserMapper.class); try { //获取第1页,10条内容,默认查询总数count PageHelper.orderBy("id desc"); User user = new User(); user.setName("刘"); List list = userMapper.selectLike(user); assertEquals(92, list.get(0).getId()); assertEquals(15, list.size()); assertEquals(15, ((Page) list).getTotal()); } finally { sqlSession.close(); } } /** * 使用Mapper接口调用时,使用PageHelper.startPage效果更好,不需要添加Mapper接口参数 */ @Test public void testMapperWithStartPage_OrderBy_issues_641() { SqlSession sqlSession = MybatisHelper.getSqlSession(); UserMapper userMapper = sqlSession.getMapper(UserMapper.class); try { //获取第1页,10条内容,默认查询总数count PageHelper.startPage(1, 0, false, false, true); PageHelper.orderBy("id desc"); User user = new User(); user.setName("刘"); List list = userMapper.selectLike(user); assertEquals(92, list.get(0).getId()); assertEquals(15, list.size()); assertEquals(15, ((Page) list).getTotal()); } finally { sqlSession.close(); } } } ================================================ FILE: src/test/java/com/github/pagehelper/test/basic/TestNamespaceMap.java ================================================ /* * The MIT License (MIT) * * Copyright (c) 2014-2023 abel533@gmail.com * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ package com.github.pagehelper.test.basic; import com.github.pagehelper.Page; import com.github.pagehelper.PageHelper; import com.github.pagehelper.model.User; import com.github.pagehelper.util.MybatisHelper; import org.apache.ibatis.session.SqlSession; import org.junit.Test; import java.util.HashMap; import java.util.List; import java.util.Map; import static org.junit.Assert.assertEquals; public class TestNamespaceMap { /** * 使用Mapper接口调用时,使用PageHelper.startPage效果更好,不需要添加Mapper接口参数 */ @Test public void testMapperWithStartPage() { SqlSession sqlSession = MybatisHelper.getSqlSession(); try { //获取第1页,10条内容,默认查询总数count PageHelper.startPage(1, 10); Map map = new HashMap(); map.put("name", "刘"); List list = sqlSession.selectList("selectLike", map); assertEquals(78, list.get(0).getId()); assertEquals(10, list.size()); assertEquals(15, ((Page) list).getTotal()); PageHelper.startPage(1, 10); map.put("name", "刘睿"); map.put("py", "LR"); list = sqlSession.selectList("selectByMap", map); assertEquals(78, list.get(0).getId()); assertEquals(1, list.size()); assertEquals(1, ((Page) list).getTotal()); } finally { sqlSession.close(); } } } ================================================ FILE: src/test/java/com/github/pagehelper/test/basic/annotations/TestAnnotations.java ================================================ /* * The MIT License (MIT) * * Copyright (c) 2014-2023 abel533@gmail.com * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ package com.github.pagehelper.test.basic.annotations; import com.github.pagehelper.Page; import com.github.pagehelper.PageHelper; import com.github.pagehelper.mapper.UserMapper; import com.github.pagehelper.model.User; import com.github.pagehelper.util.MybatisHelper; import org.apache.ibatis.session.SqlSession; import org.junit.Test; import java.util.List; import static org.junit.Assert.assertEquals; public class TestAnnotations { /** * 使用Mapper接口调用时,使用PageHelper.startPage效果更好,不需要添加Mapper接口参数 */ @Test public void testMapperWithStartPage() { SqlSession sqlSession = MybatisHelper.getSqlSession(); UserMapper userMapper = sqlSession.getMapper(UserMapper.class); try { //获取第1页,10条内容,默认查询总数count PageHelper.startPage(1, 10); List list = userMapper.selectByOrder2("id"); assertEquals(1, list.get(0).getId()); assertEquals(10, list.size()); assertEquals(183, ((Page) list).getTotal()); //获取第1页,10条内容,默认查询总数count PageHelper.startPage(1, 10); list = userMapper.selectByOrder("name"); assertEquals(18, list.get(0).getId()); assertEquals(10, list.size()); assertEquals(183, ((Page) list).getTotal()); } finally { sqlSession.close(); } } /** * 使用Mapper接口调用时,使用PageHelper.startPage效果更好,不需要添加Mapper接口参数 */ @Test public void testMapperWithStartPage_OrderBy() { SqlSession sqlSession = MybatisHelper.getSqlSession(); UserMapper userMapper = sqlSession.getMapper(UserMapper.class); try { //获取第1页,10条内容,默认查询总数count PageHelper.startPage(1, 10, "id desc"); List list = userMapper.selectByOrder2("id"); assertEquals(183, list.get(0).getId()); assertEquals(10, list.size()); assertEquals(183, ((Page) list).getTotal()); //获取第1页,10条内容,默认查询总数count PageHelper.startPage(1, 10, "id desc"); list = userMapper.selectByOrder("name"); assertEquals(183, list.get(0).getId()); assertEquals(10, list.size()); assertEquals(183, ((Page) list).getTotal()); } finally { sqlSession.close(); } } } ================================================ FILE: src/test/java/com/github/pagehelper/test/basic/cache/CacheTest.java ================================================ /* * The MIT License (MIT) * * Copyright (c) 2014-2023 abel533@gmail.com * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ package com.github.pagehelper.test.basic.cache; import com.github.pagehelper.PageHelper; import com.github.pagehelper.mapper.UserMapper; import com.github.pagehelper.model.User; import com.github.pagehelper.util.MybatisHelper; import org.apache.ibatis.session.SqlSession; import org.junit.Test; import java.util.List; import static org.junit.Assert.assertEquals; /** * 针对将ms缓存后的测试 */ public class CacheTest { /** * 使用Mapper接口调用时,使用PageHelper.startPage效果更好,不需要添加Mapper接口参数 */ @Test public void testMapperWithStartPage() { SqlSession sqlSession = MybatisHelper.getSqlSession(); UserMapper userMapper = sqlSession.getMapper(UserMapper.class); try { //获取第1页,10条内容,默认查询总数count PageHelper.startPage(1, 10); List list = userMapper.selectGreterThanId(10); assertEquals(10, list.size()); //获取第1页,10条内容,默认查询总数count PageHelper.startPage(2, 10); list = userMapper.selectGreterThanIdAndNotEquelName(10, "刘睿"); assertEquals(10, list.size()); //获取第1页,10条内容,默认查询总数count PageHelper.startPage(3, 10); list = userMapper.selectGreterThanIdAndNotEquelName(10, "刘睿"); assertEquals(10, list.size()); //获取第1页,10条内容,默认查询总数count PageHelper.startPage(4, 10); list = userMapper.selectGreterThanIdAndNotEquelName(10, "刘睿"); assertEquals(10, list.size()); //获取第1页,10条内容,默认查询总数count PageHelper.startPage(5, 10); list = userMapper.selectGreterThanIdAndNotEquelName(10, "刘睿"); assertEquals(10, list.size()); } finally { sqlSession.close(); } } /** * 使用Mapper接口调用时,使用PageHelper.startPage效果更好,不需要添加Mapper接口参数 */ @Test public void testThreads() { SqlSession sqlSession = MybatisHelper.getSqlSession(); sqlSession.close(); try { Thread.sleep(300); } catch (InterruptedException e) { e.printStackTrace(); } Thread thread1 = new Thread(new CacheThread()); Thread thread2 = new Thread(new CacheThread()); Thread thread3 = new Thread(new CacheThread()); Thread thread4 = new Thread(new CacheThread()); Thread thread5 = new Thread(new CacheThread()); thread1.start(); thread2.start(); thread3.start(); thread4.start(); thread5.start(); try { Thread.sleep(300); } catch (InterruptedException e) { e.printStackTrace(); } } private class CacheThread implements Runnable { private CacheThread() { } public void run() { SqlSession sqlSession = MybatisHelper.getSqlSession(); System.out.println(Thread.currentThread().getId() + "开始运行..."); UserMapper userMapper = sqlSession.getMapper(UserMapper.class); //获取第1页,10条内容,默认查询总数count PageHelper.startPage(1, 10); List list = userMapper.selectGreterThanIdAndNotEquelName(10, "刘睿"); assertEquals(10, list.size()); //获取第2页,10条内容,默认查询总数count PageHelper.startPage(2, 10); list = userMapper.selectGreterThanIdAndNotEquelName(10, "刘睿"); assertEquals(10, list.size()); sqlSession.close(); } } } ================================================ FILE: src/test/java/com/github/pagehelper/test/basic/cache/SecondCacheTest.java ================================================ /* * The MIT License (MIT) * * Copyright (c) 2014-2023 abel533@gmail.com * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ package com.github.pagehelper.test.basic.cache; import com.github.pagehelper.PageHelper; import com.github.pagehelper.mapper.UserMapper; import com.github.pagehelper.model.User; import com.github.pagehelper.util.MybatisHelper; import org.apache.ibatis.session.SqlSession; import org.junit.Test; import java.util.List; import static org.junit.Assert.assertEquals; public class SecondCacheTest { @Test public void test1() { SqlSession sqlSession = MybatisHelper.getSqlSession(); UserMapper userMapper = sqlSession.getMapper(UserMapper.class); try { //获取第1页,10条内容,默认查询总数count PageHelper.startPage(1, 10); List list = userMapper.selectGreterThanId(10); assertEquals(10, list.size()); //获取第1页,10条内容,默认查询总数count PageHelper.startPage(1, 10); list = userMapper.selectGreterThanId(10); assertEquals(10, list.size()); } finally { sqlSession.close(); } sqlSession = MybatisHelper.getSqlSession(); userMapper = sqlSession.getMapper(UserMapper.class); try { //获取第1页,10条内容,默认查询总数count PageHelper.startPage(1, 10); List list = userMapper.selectGreterThanId(10); assertEquals(10, list.size()); } finally { sqlSession.close(); } } @Test public void test2() { SqlSession sqlSession = MybatisHelper.getSqlSession(); UserMapper userMapper = sqlSession.getMapper(UserMapper.class); try { //获取第1页,10条内容,默认查询总数count PageHelper.startPage(1, 10); List list = userMapper.selectGreterThanId(10); assertEquals(10, list.size()); } finally { sqlSession.close(); } } @Test public void test3() { SqlSession sqlSession = MybatisHelper.getSqlSession(); UserMapper userMapper = sqlSession.getMapper(UserMapper.class); try { //获取第1页,10条内容,默认查询总数count PageHelper.startPage(1, 10); List list = userMapper.selectGreterThanId(10); assertEquals(10, list.size()); } finally { sqlSession.close(); } } } ================================================ FILE: src/test/java/com/github/pagehelper/test/basic/count/TestGroupBy.java ================================================ /* * The MIT License (MIT) * * Copyright (c) 2014-2023 abel533@gmail.com * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ package com.github.pagehelper.test.basic.count; import com.github.pagehelper.Page; import com.github.pagehelper.PageHelper; import com.github.pagehelper.PageInfo; import com.github.pagehelper.mapper.UserMapper; import com.github.pagehelper.model.User; import com.github.pagehelper.util.MybatisHelper; import org.apache.ibatis.session.SqlSession; import org.junit.Test; import static org.junit.Assert.assertEquals; public class TestGroupBy { @Test public void testGroupBy() { SqlSession sqlSession = MybatisHelper.getSqlSession(); UserMapper userMapper = sqlSession.getMapper(UserMapper.class); try { //获取第1页,10条内容,默认查询总数count Page page = PageHelper.startPage(1, 10); userMapper.selectGroupBy(); //1,'Angola','AO' assertEquals(1, page.get(0).getId()); assertEquals(10, page.size()); assertEquals(183, page.getTotal()); PageInfo pageInfo = page.toPageInfo(); System.out.println(pageInfo); //获取第2页,10条内容,默认查询总数count page = PageHelper.startPage(2, 10); userMapper.selectGroupBy(); //1,'Angola','AO' assertEquals(1, page.get(0).getId()); assertEquals(10, page.size()); assertEquals(183, page.getTotal()); } finally { sqlSession.close(); } } } ================================================ FILE: src/test/java/com/github/pagehelper/test/basic/count/TestOrderBy.java ================================================ package com.github.pagehelper.test.basic.count; import com.github.pagehelper.Page; import com.github.pagehelper.PageHelper; import com.github.pagehelper.mapper.UserMapper; import com.github.pagehelper.model.User; import com.github.pagehelper.util.MybatisHelper; import org.apache.ibatis.session.SqlSession; import org.junit.Test; import java.util.List; import static org.junit.Assert.assertEquals; /** * Test for ORDER BY with parameters - issue #868 * * @author pwdLight (original fix) * @description Test that ORDER BY containing parameters is not removed in count * query * @date 2025/10/22 */ public class TestOrderBy { /** * Test ORDER BY with parameters - issue #868 * When ORDER BY contains parameters (#{param}), it should not be removed in * count query * to avoid JDBC parameter mismatch */ @Test public void testOrderByWithParameters() { SqlSession sqlSession = MybatisHelper.getSqlSession(); UserMapper userMapper = sqlSession.getMapper(UserMapper.class); try { // Test with ORDER BY containing parameter binding (#{py}) // This will generate ORDER BY with ? placeholder PageHelper.startPage(1, 10); List list = userMapper.selectOrderByWithParam("ZSJ"); // Verify pagination works correctly assertEquals(10, list.size()); assertEquals(183, ((Page) list).getTotal()); } finally { sqlSession.close(); } } /** * Test ORDER BY without parameters - should use simple count optimization */ @Test public void testOrderByWithoutParameters() { SqlSession sqlSession = MybatisHelper.getSqlSession(); UserMapper userMapper = sqlSession.getMapper(UserMapper.class); try { // Test with simple ORDER BY (no parameters) PageHelper.startPage(1, 10); List list = userMapper.selectAllOrderby(); // Verify pagination works correctly assertEquals(10, list.size()); assertEquals(183, ((Page) list).getTotal()); } finally { sqlSession.close(); } } } ================================================ FILE: src/test/java/com/github/pagehelper/test/basic/count/TestSelectItems.java ================================================ /* * The MIT License (MIT) * * Copyright (c) 2014-2023 abel533@gmail.com * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ package com.github.pagehelper.test.basic.count; import com.github.pagehelper.Page; import com.github.pagehelper.PageHelper; import com.github.pagehelper.mapper.UserMapper; import com.github.pagehelper.model.User; import com.github.pagehelper.util.MybatisHelper; import org.apache.ibatis.session.SqlSession; import org.junit.Test; import java.util.List; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNull; public class TestSelectItems { /** * 查询自定义列时 - 实际上这个测试由于使用${},并没有起到真正的目的 */ @Test public void testSelectColumns() { SqlSession sqlSession = MybatisHelper.getSqlSession(); UserMapper userMapper = sqlSession.getMapper(UserMapper.class); try { //获取第1页,10条内容,默认查询总数count PageHelper.startPage(1, 10); List list = userMapper.selectColumns(); //1,'Angola','AO' assertEquals(1, list.get(0).getId()); assertEquals("毕淑儒", list.get(0).getName()); assertEquals("BSR", list.get(0).getPy()); assertEquals(10, list.size()); assertEquals(183, ((Page) list).getTotal()); //获取第1页,10条内容,默认查询总数count PageHelper.startPage(1, 10); list = userMapper.selectColumns("id", "name"); //1,'Angola','AO' assertEquals(1, list.get(0).getId()); assertEquals("毕淑儒", list.get(0).getName()); assertNull(list.get(0).getPy()); assertEquals(10, list.size()); assertEquals(183, ((Page) list).getTotal()); } finally { sqlSession.close(); } } /** * 使用#{}在查询列中进行计算,count查询时需要特殊对待 */ @Test public void testSelectColumn2() { SqlSession sqlSession = MybatisHelper.getSqlSession(); UserMapper userMapper = sqlSession.getMapper(UserMapper.class); try { //获取第1页,10条内容,默认查询总数count PageHelper.startPage(1, 10); List list = userMapper.selectMULId(1); //1,'Angola','AO' assertEquals(1, list.get(0).getId()); assertEquals(10, list.size()); assertEquals(183, ((Page) list).getTotal()); //获取第1页,10条内容,默认查询总数count PageHelper.startPage(1, 10); list = userMapper.selectMULId(5); //1,'Angola','AO' assertEquals(5, list.get(0).getId()); assertEquals(10, list.size()); assertEquals(183, ((Page) list).getTotal()); } finally { sqlSession.close(); } } } ================================================ FILE: src/test/java/com/github/pagehelper/test/basic/dynamic/CacheTest.java ================================================ /* * The MIT License (MIT) * * Copyright (c) 2014-2023 abel533@gmail.com * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ package com.github.pagehelper.test.basic.dynamic; import com.github.pagehelper.Page; import com.github.pagehelper.PageHelper; import com.github.pagehelper.mapper.UserMapper; import com.github.pagehelper.model.User; import com.github.pagehelper.util.MybatisHelper; import org.apache.ibatis.session.SqlSession; import org.junit.Test; import java.util.Arrays; import java.util.List; import static org.junit.Assert.assertEquals; /** * 针对将ms缓存后的测试 */ public class CacheTest { /** * 使用Mapper接口调用时,使用PageHelper.startPage效果更好,不需要添加Mapper接口参数 */ @Test public void testThreads() { SqlSession sqlSession = MybatisHelper.getSqlSession(); sqlSession.close(); try { Thread.sleep(300); } catch (InterruptedException e) { e.printStackTrace(); } Thread thread1 = new Thread(new CacheThread()); Thread thread2 = new Thread(new CacheThread()); Thread thread3 = new Thread(new CacheThread()); Thread thread4 = new Thread(new CacheThread()); Thread thread5 = new Thread(new CacheThread()); thread1.start(); thread2.start(); thread3.start(); thread4.start(); thread5.start(); try { Thread.sleep(300); } catch (InterruptedException e) { e.printStackTrace(); } } private class CacheThread implements Runnable { private CacheThread() { } public void run() { SqlSession sqlSession = MybatisHelper.getSqlSession(); System.out.println(Thread.currentThread().getId() + "开始运行..."); UserMapper userMapper = sqlSession.getMapper(UserMapper.class); //获取第1页,10条内容,默认查询总数count PageHelper.startPage(1, 10); List list = userMapper.selectIf2List(Arrays.asList(1, 2), Arrays.asList(3, 4)); assertEquals(5, list.get(0).getId()); assertEquals(10, list.size()); assertEquals(179, ((Page) list).getTotal()); //获取第1页,10条内容,默认查询总数count PageHelper.startPage(1, 10); list = userMapper.selectIf2List(Arrays.asList(1, 2), null); assertEquals(3, list.get(0).getId()); assertEquals(10, list.size()); assertEquals(181, ((Page) list).getTotal()); sqlSession.close(); } } } ================================================ FILE: src/test/java/com/github/pagehelper/test/basic/dynamic/TestDynamicChoose.java ================================================ /* * The MIT License (MIT) * * Copyright (c) 2014-2023 abel533@gmail.com * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ package com.github.pagehelper.test.basic.dynamic; import com.github.pagehelper.Page; import com.github.pagehelper.PageHelper; import com.github.pagehelper.mapper.UserMapper; import com.github.pagehelper.model.User; import com.github.pagehelper.util.MybatisHelper; import org.apache.ibatis.session.SqlSession; import org.junit.Test; import java.util.List; import static org.junit.Assert.assertEquals; public class TestDynamicChoose { /** * 使用Mapper接口调用时,使用PageHelper.startPage效果更好,不需要添加Mapper接口参数 */ @Test public void testMapperWithStartPage() { SqlSession sqlSession = MybatisHelper.getSqlSession(); UserMapper userMapper = sqlSession.getMapper(UserMapper.class); try { //获取第1页,10条内容,默认查询总数count PageHelper.startPage(1, 10); List list = userMapper.selectChoose(1, 2); assertEquals(2, list.get(0).getId()); assertEquals(10, list.size()); assertEquals(182, ((Page) list).getTotal()); //获取第1页,10条内容,默认查询总数count PageHelper.startPage(1, 10); list = userMapper.selectChoose(1, 2); assertEquals(2, list.get(0).getId()); assertEquals(10, list.size()); assertEquals(182, ((Page) list).getTotal()); } finally { sqlSession.close(); } } /** * 使用Mapper接口调用时,使用PageHelper.startPage效果更好,不需要添加Mapper接口参数 */ @Test public void testMapperWithStartPage_OrderBy() { SqlSession sqlSession = MybatisHelper.getSqlSession(); UserMapper userMapper = sqlSession.getMapper(UserMapper.class); try { //获取第1页,10条内容,默认查询总数count PageHelper.startPage(1, 10, "id desc"); List list = userMapper.selectChoose(183, 2); assertEquals(182, list.get(0).getId()); assertEquals(10, list.size()); assertEquals(182, ((Page) list).getTotal()); //获取第1页,10条内容,默认查询总数count PageHelper.startPage(1, 10, "id desc"); list = userMapper.selectChoose(183, 2); assertEquals(182, list.get(0).getId()); assertEquals(10, list.size()); assertEquals(182, ((Page) list).getTotal()); } finally { sqlSession.close(); } } } ================================================ FILE: src/test/java/com/github/pagehelper/test/basic/dynamic/TestDynamicForeach.java ================================================ /* * The MIT License (MIT) * * Copyright (c) 2014-2023 abel533@gmail.com * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ package com.github.pagehelper.test.basic.dynamic; import com.github.pagehelper.Page; import com.github.pagehelper.PageHelper; import com.github.pagehelper.mapper.UserMapper; import com.github.pagehelper.model.User; import com.github.pagehelper.util.MybatisHelper; import org.apache.ibatis.session.SqlSession; import org.junit.Test; import java.util.ArrayList; import java.util.List; import static org.junit.Assert.assertEquals; public class TestDynamicForeach { /** * 使用Mapper接口调用时,使用PageHelper.startPage效果更好,不需要添加Mapper接口参数 */ @Test public void testMapperWithStartPage() { SqlSession sqlSession = MybatisHelper.getSqlSession(); UserMapper userMapper = sqlSession.getMapper(UserMapper.class); try { //获取第1页,10条内容,默认查询总数count List idList = new ArrayList(); idList.add(1L); idList.add(2L); idList.add(3L); PageHelper.startPage(1, 2); List list = userMapper.selectByIdList(idList); assertEquals(1, list.get(0).getId()); assertEquals(2, list.size()); assertEquals(3, ((Page) list).getTotal()); } finally { sqlSession.close(); } } /** * 使用Mapper接口调用时,使用PageHelper.startPage效果更好,不需要添加Mapper接口参数 */ @Test public void testMapperWithStartPage2() { SqlSession sqlSession = MybatisHelper.getSqlSession(); UserMapper userMapper = sqlSession.getMapper(UserMapper.class); try { //获取第1页,10条内容,默认查询总数count List idList = new ArrayList(); idList.add(1L); idList.add(2L); idList.add(3L); PageHelper.startPage(1, 2); List list = userMapper.selectByIdList2(idList); assertEquals(1, list.get(0).getId()); assertEquals(2, list.size()); assertEquals(3, ((Page) list).getTotal()); } finally { sqlSession.close(); } } } ================================================ FILE: src/test/java/com/github/pagehelper/test/basic/dynamic/TestDynamicIf.java ================================================ /* * The MIT License (MIT) * * Copyright (c) 2014-2023 abel533@gmail.com * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ package com.github.pagehelper.test.basic.dynamic; import com.github.pagehelper.Page; import com.github.pagehelper.PageHelper; import com.github.pagehelper.mapper.UserMapper; import com.github.pagehelper.model.User; import com.github.pagehelper.util.MybatisHelper; import org.apache.ibatis.session.SqlSession; import org.junit.Test; import java.util.HashMap; import java.util.List; import java.util.Map; import static org.junit.Assert.assertEquals; public class TestDynamicIf { /** * 使用Mapper接口调用时,使用PageHelper.startPage效果更好,不需要添加Mapper接口参数 */ @Test public void testCountCache() { SqlSession sqlSession = MybatisHelper.getSqlSession(); UserMapper userMapper = sqlSession.getMapper(UserMapper.class); try { //获取第1页,10条内容,默认查询总数count PageHelper.startPage(1, 10); List list = userMapper.selectIf(1); assertEquals(2, list.get(0).getId()); assertEquals(10, list.size()); assertEquals(182, ((Page) list).getTotal()); //获取第1页,10条内容,默认查询总数count PageHelper.startPage(1, 10); list = userMapper.selectIf(null); assertEquals(1, list.get(0).getId()); assertEquals(10, list.size()); assertEquals(183, ((Page) list).getTotal()); } finally { sqlSession.close(); } } /** * 使用Mapper接口调用时,使用PageHelper.startPage效果更好,不需要添加Mapper接口参数 */ @Test public void testCountCache2() { SqlSession sqlSession = MybatisHelper.getSqlSession(); UserMapper userMapper = sqlSession.getMapper(UserMapper.class); try { //获取第1页,10条内容,默认查询总数count PageHelper.startPage(1, 10); List list = userMapper.selectIf(1); assertEquals(2, list.get(0).getId()); assertEquals(10, list.size()); assertEquals(182, ((Page) list).getTotal()); //获取第1页,10条内容,默认查询总数count PageHelper.startPage(2, 10); list = userMapper.selectIf(1); assertEquals(12, list.get(0).getId()); assertEquals(10, list.size()); assertEquals(182, ((Page) list).getTotal()); } finally { sqlSession.close(); } } /** * 单个POJO参数情况特殊 */ @SuppressWarnings({"rawtypes", "unchecked"}) @Test public void testMapper() { SqlSession sqlSession = MybatisHelper.getSqlSession(); UserMapper userMapper = sqlSession.getMapper(UserMapper.class); try { Map map = new HashMap(); User user = new User(); user.setId(1); map.put("user", user); //获取第1页,10条内容,默认查询总数count PageHelper.startPage(1, 10); List list = userMapper.selectIf3(user); assertEquals(2, list.get(0).getId()); assertEquals(10, list.size()); assertEquals(182, ((Page) list).getTotal()); } finally { sqlSession.close(); } } } ================================================ FILE: src/test/java/com/github/pagehelper/test/basic/dynamic/TestDynamicIf2.java ================================================ /* * The MIT License (MIT) * * Copyright (c) 2014-2023 abel533@gmail.com * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ package com.github.pagehelper.test.basic.dynamic; import com.github.pagehelper.Page; import com.github.pagehelper.PageHelper; import com.github.pagehelper.mapper.UserMapper; import com.github.pagehelper.model.User; import com.github.pagehelper.util.MybatisHelper; import org.apache.ibatis.session.SqlSession; import org.junit.Test; import java.util.List; import static org.junit.Assert.assertEquals; public class TestDynamicIf2 { /** * 使用Mapper接口调用时,使用PageHelper.startPage效果更好,不需要添加Mapper接口参数 */ @Test public void testMapperWithStartPage() { SqlSession sqlSession = MybatisHelper.getSqlSession(); UserMapper userMapper = sqlSession.getMapper(UserMapper.class); try { //获取第1页,10条内容,默认查询总数count PageHelper.startPage(1, 10); List list = userMapper.selectIf2(1, 2); assertEquals(3, list.get(0).getId()); assertEquals(10, list.size()); assertEquals(181, ((Page) list).getTotal()); //获取第1页,10条内容,默认查询总数count PageHelper.startPage(1, 10); list = userMapper.selectIf2(1, null); assertEquals(2, list.get(0).getId()); assertEquals(10, list.size()); assertEquals(182, ((Page) list).getTotal()); } finally { sqlSession.close(); } } } ================================================ FILE: src/test/java/com/github/pagehelper/test/basic/dynamic/TestDynamicIfOrder.java ================================================ /* * The MIT License (MIT) * * Copyright (c) 2014-2023 abel533@gmail.com * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ package com.github.pagehelper.test.basic.dynamic; import com.github.pagehelper.Page; import com.github.pagehelper.PageHelper; import com.github.pagehelper.mapper.UserMapper; import com.github.pagehelper.model.User; import com.github.pagehelper.util.MybatisHelper; import org.apache.ibatis.session.SqlSession; import org.junit.Test; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import static org.junit.Assert.assertEquals; /** * 针对将ms缓存后的测试 */ public class TestDynamicIfOrder { /** * 使用Mapper接口调用时,使用PageHelper.startPage效果更好,不需要添加Mapper接口参数 */ @Test public void testMapperWithStartPage() { SqlSession sqlSession = MybatisHelper.getSqlSession(); UserMapper userMapper = sqlSession.getMapper(UserMapper.class); try { //获取第1页,10条内容,默认查询总数count PageHelper.startPage(1, 10); List list = userMapper.selectIf2ListAndOrder(Arrays.asList(1, 2), Arrays.asList(3, 4), null); assertEquals(5, list.get(0).getId()); assertEquals(10, list.size()); assertEquals(179, ((Page) list).getTotal()); //获取第1页,10条内容,默认查询总数count PageHelper.startPage(1, 10); list = userMapper.selectIf2ListAndOrder(Arrays.asList(1, 2), null, "id"); assertEquals(3, list.get(0).getId()); assertEquals(10, list.size()); assertEquals(181, ((Page) list).getTotal()); //获取第1页,10条内容,默认查询总数count PageHelper.startPage(1, 10); list = userMapper.selectIf2ListAndOrder(new ArrayList(0), null, "name"); assertEquals(18, list.get(0).getId()); assertEquals(10, list.size()); assertEquals(183, ((Page) list).getTotal()); } finally { sqlSession.close(); } } } ================================================ FILE: src/test/java/com/github/pagehelper/test/basic/dynamic/TestDynamicIfTwoList.java ================================================ /* * The MIT License (MIT) * * Copyright (c) 2014-2023 abel533@gmail.com * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ package com.github.pagehelper.test.basic.dynamic; import com.github.pagehelper.Page; import com.github.pagehelper.PageHelper; import com.github.pagehelper.mapper.UserMapper; import com.github.pagehelper.model.User; import com.github.pagehelper.util.MybatisHelper; import org.apache.ibatis.session.SqlSession; import org.junit.Test; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import static org.junit.Assert.assertEquals; public class TestDynamicIfTwoList { /** * 使用Mapper接口调用时,使用PageHelper.startPage效果更好,不需要添加Mapper接口参数 */ @Test public void testMapperWithStartPage() { SqlSession sqlSession = MybatisHelper.getSqlSession(); UserMapper userMapper = sqlSession.getMapper(UserMapper.class); try { //获取第1页,10条内容,默认查询总数count PageHelper.startPage(1, 10); List list = userMapper.selectIf2List(Arrays.asList(1, 2), Arrays.asList(3, 4)); assertEquals(5, list.get(0).getId()); assertEquals(10, list.size()); assertEquals(179, ((Page) list).getTotal()); //获取第1页,10条内容,默认查询总数count PageHelper.startPage(1, 10); list = userMapper.selectIf2List(Arrays.asList(1, 2), null); assertEquals(3, list.get(0).getId()); assertEquals(10, list.size()); assertEquals(181, ((Page) list).getTotal()); //获取第1页,10条内容,默认查询总数count PageHelper.startPage(1, 10); list = userMapper.selectIf2List(new ArrayList(0), null); assertEquals(1, list.get(0).getId()); assertEquals(10, list.size()); assertEquals(183, ((Page) list).getTotal()); } finally { sqlSession.close(); } } } ================================================ FILE: src/test/java/com/github/pagehelper/test/basic/dynamic/TestDynamicWhere.java ================================================ /* * The MIT License (MIT) * * Copyright (c) 2014-2023 abel533@gmail.com * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ package com.github.pagehelper.test.basic.dynamic; import com.github.pagehelper.Page; import com.github.pagehelper.PageHelper; import com.github.pagehelper.mapper.UserMapper; import com.github.pagehelper.model.User; import com.github.pagehelper.util.MybatisHelper; import org.apache.ibatis.session.SqlSession; import org.junit.Test; import java.util.HashMap; import java.util.List; import java.util.Map; import static org.junit.Assert.assertEquals; public class TestDynamicWhere { @Test public void testMapperWithStartPage() { SqlSession sqlSession = MybatisHelper.getSqlSession(); UserMapper userMapper = sqlSession.getMapper(UserMapper.class); try { //获取第1页,10条内容,默认查询总数count Map params = new HashMap(2); params.put("pageNum", 1L); params.put("pageSize", "100"); PageHelper.startPage(params); Map where = new HashMap(); where.put("id", 100); List list = userMapper.selectByWhereMap(new Where(where)); assertEquals(100, list.get(0).getId()); assertEquals(1, list.size()); assertEquals(1, ((Page) list).getTotal()); } finally { sqlSession.close(); } } } ================================================ FILE: src/test/java/com/github/pagehelper/test/basic/dynamic/Where.java ================================================ /* * The MIT License (MIT) * * Copyright (c) 2014-2023 abel533@gmail.com * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ package com.github.pagehelper.test.basic.dynamic; import java.util.Map; /** * Created by liuzh on 2015/1/11. */ public class Where { private Map map; public Where(Map map) { this.map = map; } public Map getMap() { return map; } public void setMap(Map map) { this.map = map; } } ================================================ FILE: src/test/java/com/github/pagehelper/test/basic/example/TestExample.java ================================================ /* * The MIT License (MIT) * * Copyright (c) 2014-2023 abel533@gmail.com * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ package com.github.pagehelper.test.basic.example; import com.github.pagehelper.Page; import com.github.pagehelper.PageHelper; import com.github.pagehelper.mapper.UserMapper; import com.github.pagehelper.model.User; import com.github.pagehelper.model.UserExample; import com.github.pagehelper.util.MybatisHelper; import org.apache.ibatis.session.SqlSession; import org.junit.Test; import java.util.Arrays; import java.util.List; import static org.junit.Assert.assertEquals; public class TestExample { @Test public void testNull() { SqlSession sqlSession = MybatisHelper.getSqlSession(); UserMapper userMapper = sqlSession.getMapper(UserMapper.class); try { PageHelper.startPage(1, 20); List list = userMapper.selectByExample(null); assertEquals(1, list.get(0).getId()); assertEquals(20, list.size()); assertEquals(183, ((Page) list).getTotal()); } finally { sqlSession.close(); } } @Test public void testGreaterThan() { SqlSession sqlSession = MybatisHelper.getSqlSession(); UserMapper userMapper = sqlSession.getMapper(UserMapper.class); try { UserExample example = new UserExample(); example.createCriteria().andIdGreaterThan(100); PageHelper.startPage(1, 20); List list = userMapper.selectByExample(example); assertEquals(101, list.get(0).getId()); assertEquals(20, list.size()); assertEquals(83, ((Page) list).getTotal()); } finally { sqlSession.close(); } } @Test public void testInList() { SqlSession sqlSession = MybatisHelper.getSqlSession(); UserMapper userMapper = sqlSession.getMapper(UserMapper.class); try { UserExample example = new UserExample(); example.createCriteria().andIdIn(Arrays.asList(1, 2, 3, 4, 5)); PageHelper.startPage(1, 20); List list = userMapper.selectByExample(example); assertEquals(1, list.get(0).getId()); assertEquals(5, list.size()); assertEquals(5, ((Page) list).getTotal()); } finally { sqlSession.close(); } } } ================================================ FILE: src/test/java/com/github/pagehelper/test/basic/parameter/TestParameterArray.java ================================================ /* * The MIT License (MIT) * * Copyright (c) 2014-2023 abel533@gmail.com * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ package com.github.pagehelper.test.basic.parameter; import com.github.pagehelper.Page; import com.github.pagehelper.PageHelper; import com.github.pagehelper.mapper.UserMapper; import com.github.pagehelper.model.User; import com.github.pagehelper.util.MybatisHelper; import org.apache.ibatis.session.SqlSession; import org.junit.Test; import java.util.List; import static org.junit.Assert.assertEquals; public class TestParameterArray { /** * 使用Mapper接口调用时,使用PageHelper.startPage效果更好,不需要添加Mapper接口参数 */ @Test public void testMapperWithStartPage() { SqlSession sqlSession = MybatisHelper.getSqlSession(); UserMapper userMapper = sqlSession.getMapper(UserMapper.class); try { //获取第1页,10条内容,默认查询总数count PageHelper.startPage(1, 10); List list = userMapper.selectAllOrderByArray(new Integer[]{1, 2}); assertEquals(3, list.get(0).getId()); assertEquals(10, list.size()); assertEquals(181, ((Page) list).getTotal()); } finally { sqlSession.close(); } } } ================================================ FILE: src/test/java/com/github/pagehelper/test/basic/parameter/TestParameterList.java ================================================ /* * The MIT License (MIT) * * Copyright (c) 2014-2023 abel533@gmail.com * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ package com.github.pagehelper.test.basic.parameter; import com.github.pagehelper.Page; import com.github.pagehelper.PageHelper; import com.github.pagehelper.mapper.UserMapper; import com.github.pagehelper.model.User; import com.github.pagehelper.util.MybatisHelper; import org.apache.ibatis.session.SqlSession; import org.junit.Test; import java.util.ArrayList; import java.util.List; import static org.junit.Assert.assertEquals; public class TestParameterList { /** * 使用Mapper接口调用时,使用PageHelper.startPage效果更好,不需要添加Mapper接口参数 */ @Test public void testMapperWithStartPage() { SqlSession sqlSession = MybatisHelper.getSqlSession(); UserMapper userMapper = sqlSession.getMapper(UserMapper.class); try { //获取第1页,10条内容,默认查询总数count List paList = new ArrayList(); paList.add(1); paList.add(2); PageHelper.startPage(1, 10); List list = userMapper.selectAllOrderByList(paList); assertEquals(3, list.get(0).getId()); assertEquals(10, list.size()); assertEquals(181, ((Page) list).getTotal()); } finally { sqlSession.close(); } } } ================================================ FILE: src/test/java/com/github/pagehelper/test/basic/parameter/TestParameterMap.java ================================================ /* * The MIT License (MIT) * * Copyright (c) 2014-2023 abel533@gmail.com * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ package com.github.pagehelper.test.basic.parameter; import com.github.pagehelper.Page; import com.github.pagehelper.PageHelper; import com.github.pagehelper.mapper.UserMapper; import com.github.pagehelper.model.User; import com.github.pagehelper.util.MybatisHelper; import org.apache.ibatis.session.SqlSession; import org.junit.Test; import java.util.HashMap; import java.util.List; import java.util.Map; import static org.junit.Assert.assertEquals; public class TestParameterMap { /** * 使用Mapper接口调用时,使用PageHelper.startPage效果更好,不需要添加Mapper接口参数 */ @Test public void testMapperWithStartPage() { SqlSession sqlSession = MybatisHelper.getSqlSession(); UserMapper userMapper = sqlSession.getMapper(UserMapper.class); try { //获取第1页,10条内容,默认查询总数count Map map = new HashMap(); map.put("order1", 1); map.put("order2", 2); map.put("tableName", "user"); PageHelper.startPage(1, 10); List list = userMapper.selectAllOrderByMap(map); assertEquals(3, list.get(0).getId()); assertEquals(10, list.size()); assertEquals(181, ((Page) list).getTotal()); map.put("tableName", "user a"); PageHelper.startPage(1, 10); list = userMapper.selectAllOrderByMap(map); assertEquals(3, list.get(0).getId()); assertEquals(10, list.size()); assertEquals(181, ((Page) list).getTotal()); } finally { sqlSession.close(); } } } ================================================ FILE: src/test/java/com/github/pagehelper/test/basic/parameter/TestParameterNone.java ================================================ /* * The MIT License (MIT) * * Copyright (c) 2014-2023 abel533@gmail.com * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ package com.github.pagehelper.test.basic.parameter; import com.github.pagehelper.Page; import com.github.pagehelper.PageHelper; import com.github.pagehelper.mapper.UserMapper; import com.github.pagehelper.model.User; import com.github.pagehelper.util.MybatisHelper; import org.apache.ibatis.session.SqlSession; import org.junit.Test; import java.util.List; import static org.junit.Assert.assertEquals; public class TestParameterNone { /** * 使用Mapper接口调用时,使用PageHelper.startPage效果更好,不需要添加Mapper接口参数 */ @Test public void testMapperWithStartPage() { SqlSession sqlSession = MybatisHelper.getSqlSession(); UserMapper userMapper = sqlSession.getMapper(UserMapper.class); try { //获取第1页,10条内容,默认查询总数count PageHelper.startPage(1, 10); List list = userMapper.selectAll(); assertEquals(1, list.get(0).getId()); assertEquals(10, list.size()); assertEquals(183, ((Page) list).getTotal()); } finally { sqlSession.close(); } } } ================================================ FILE: src/test/java/com/github/pagehelper/test/basic/parameter/TestParameterOne.java ================================================ /* * The MIT License (MIT) * * Copyright (c) 2014-2023 abel533@gmail.com * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ package com.github.pagehelper.test.basic.parameter; import com.github.pagehelper.Page; import com.github.pagehelper.PageHelper; import com.github.pagehelper.mapper.UserMapper; import com.github.pagehelper.model.User; import com.github.pagehelper.util.MybatisHelper; import org.apache.ibatis.session.SqlSession; import org.junit.Test; import java.util.List; import static org.junit.Assert.assertEquals; public class TestParameterOne { /** * 使用Mapper接口调用时,使用PageHelper.startPage效果更好,不需要添加Mapper接口参数 */ @Test public void testMapperWithStartPage() { SqlSession sqlSession = MybatisHelper.getSqlSession(); UserMapper userMapper = sqlSession.getMapper(UserMapper.class); try { //获取第1页,10条内容,默认查询总数count PageHelper.startPage(1, 10); List list = userMapper.selectGreterThanId(1); assertEquals(2, list.get(0).getId()); assertEquals(10, list.size()); assertEquals(182, ((Page) list).getTotal()); } finally { sqlSession.close(); } } } ================================================ FILE: src/test/java/com/github/pagehelper/test/basic/provider/SqlCache.java ================================================ /* * The MIT License (MIT) * * Copyright (c) 2014-2023 abel533@gmail.com * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ package com.github.pagehelper.test.basic.provider; public class SqlCache { private static final ThreadLocal THREAD_LOCAL = new ThreadLocal(); public static void set(String str) { THREAD_LOCAL.set(str); } public static String get() { return THREAD_LOCAL.get(); } public static void remove() { THREAD_LOCAL.remove(); } } ================================================ FILE: src/test/java/com/github/pagehelper/test/basic/provider/SqlCacheInterceptor.java ================================================ /* * The MIT License (MIT) * * Copyright (c) 2014-2023 abel533@gmail.com * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ package com.github.pagehelper.test.basic.provider; import org.apache.ibatis.cache.CacheKey; import org.apache.ibatis.executor.Executor; import org.apache.ibatis.mapping.BoundSql; import org.apache.ibatis.mapping.MappedStatement; import org.apache.ibatis.plugin.*; import org.apache.ibatis.session.ResultHandler; import org.apache.ibatis.session.RowBounds; import java.util.Properties; @Intercepts({ @Signature(type = Executor.class, method = "query", args = {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class}), @Signature(type = Executor.class, method = "query", args = {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class, CacheKey.class, BoundSql.class}), }) public class SqlCacheInterceptor implements Interceptor { @Override public Object intercept(Invocation invocation) throws Throwable { Object[] args = invocation.getArgs(); MappedStatement ms = (MappedStatement) args[0]; Object parameter = args[1]; String sql = ms.getBoundSql(parameter).getSql(); SqlCache.set(sql); return invocation.proceed(); } @Override public Object plugin(Object target) { return Plugin.wrap(target, this); } @Override public void setProperties(Properties properties) { } } ================================================ FILE: src/test/java/com/github/pagehelper/test/basic/provider/TestBoundSqlInterceptor.java ================================================ /* * The MIT License (MIT) * * Copyright (c) 2014-2023 abel533@gmail.com * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ package com.github.pagehelper.test.basic.provider; import com.github.pagehelper.BoundSqlInterceptor; import com.github.pagehelper.util.MetaObjectUtil; import org.apache.ibatis.cache.CacheKey; import org.apache.ibatis.mapping.BoundSql; import org.apache.ibatis.reflection.MetaObject; public class TestBoundSqlInterceptor implements BoundSqlInterceptor { public static final String COMMENT = "\n /* TestBoundSqlInterceptor */\n"; @Override public BoundSql boundSql(Type type, BoundSql boundSql, CacheKey cacheKey, Chain chain) { if (type == Type.ORIGINAL) { String sql = boundSql.getSql(); MetaObject metaObject = MetaObjectUtil.forObject(boundSql); metaObject.setValue("sql", sql + COMMENT); } return chain.doBoundSql(type, boundSql, cacheKey); } } ================================================ FILE: src/test/java/com/github/pagehelper/test/basic/provider/TestProvider.java ================================================ /* * The MIT License (MIT) * * Copyright (c) 2014-2023 abel533@gmail.com * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ package com.github.pagehelper.test.basic.provider; import com.github.pagehelper.Page; import com.github.pagehelper.PageHelper; import com.github.pagehelper.mapper.UserMapper; import com.github.pagehelper.model.User; import com.github.pagehelper.util.MybatisHelper; import org.apache.ibatis.session.SqlSession; import org.junit.Test; import java.util.HashMap; import java.util.List; import java.util.Map; import static org.junit.Assert.assertEquals; public class TestProvider { @Test public void testSelectSimple() { SqlSession sqlSession = MybatisHelper.getSqlSession(); UserMapper userMapper = sqlSession.getMapper(UserMapper.class); try { PageHelper.startPage(1, 10); Page list = userMapper.selectSimple("飞"); assertEquals(24, list.get(0).getId()); assertEquals(6, list.size()); assertEquals(6, list.getTotal()); } finally { sqlSession.close(); } } @Test public void testProvider() { SqlSession sqlSession = MybatisHelper.getSqlSession(); Map map = new HashMap(); map.put("id", 100); UserMapper userMapper = sqlSession.getMapper(UserMapper.class); try { PageHelper.startPage(1, 10); List list = userMapper.selectByProvider(map); assertEquals(100, list.get(0).getId()); assertEquals(1, list.size()); assertEquals(1, ((Page) list).getTotal()); map.put("name", "不存在"); PageHelper.startPage(1, 10); list = userMapper.selectByProvider(map); assertEquals(0, list.size()); } finally { sqlSession.close(); } } @Test public void testUserProvider() { SqlSession sqlSession = MybatisHelper.getSqlSession(); User user = new User(); user.setId(100); UserMapper userMapper = sqlSession.getMapper(UserMapper.class); try { PageHelper.startPage(1, 10); List list = userMapper.selectByUserProvider(user); assertEquals(100, list.get(0).getId()); assertEquals(1, list.size()); assertEquals(1, ((Page) list).getTotal()); user.setName("不存在"); PageHelper.startPage(1, 10); list = userMapper.selectByUserProvider(user); assertEquals(0, list.size()); } finally { sqlSession.close(); } } @Test public void testUserSelect() { SqlSession sqlSession = MybatisHelper.getSqlSession(); User user = new User(); user.setId(100); UserMapper userMapper = sqlSession.getMapper(UserMapper.class); try { PageHelper.startPage(1, 10); List> userList = userMapper.selectBySelect(); System.out.println(userList.size()); } finally { sqlSession.close(); } } } ================================================ FILE: src/test/java/com/github/pagehelper/test/basic/provider/TestProviderInteceptor.java ================================================ /* * The MIT License (MIT) * * Copyright (c) 2014-2023 abel533@gmail.com * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ package com.github.pagehelper.test.basic.provider; import com.github.pagehelper.BoundSqlInterceptor; import com.github.pagehelper.PageHelper; import com.github.pagehelper.mapper.ProviderMethod; import com.github.pagehelper.mapper.UserMapper; import com.github.pagehelper.util.MybatisInterceptorHelper; import org.apache.ibatis.cache.CacheKey; import org.apache.ibatis.mapping.BoundSql; import org.apache.ibatis.session.SqlSession; import org.junit.Assert; import org.junit.Test; import java.util.Random; import static org.junit.Assert.assertEquals; public class TestProviderInteceptor { @Test public void testInterceptor() { SqlSession sqlSession = MybatisInterceptorHelper.getSqlSession(); final UserMapper userMapper = sqlSession.getMapper(UserMapper.class); try { PageHelper.startPage(1, 10).boundSqlInterceptor(new BoundSqlInterceptor() { @Override public BoundSql boundSql(Type type, BoundSql boundSql, CacheKey cacheKey, Chain chain) { System.out.println("[" + Thread.currentThread().getName() + "] - before: " + boundSql.getSql()); BoundSql doBoundSql = chain.doBoundSql(type, boundSql, cacheKey); System.out.println("[" + Thread.currentThread().getName() + "] - after: " + doBoundSql.getSql()); if (type == Type.ORIGINAL) { Assert.assertTrue(doBoundSql.getSql().contains(TestBoundSqlInterceptor.COMMENT)); } return doBoundSql; } }); final String str = "飞"; userMapper.selectSimple(str); assertEquals(new ProviderMethod().selectSimple(str), SqlCache.get()); userMapper.selectSimple(str); assertEquals(new ProviderMethod().selectSimple(str), SqlCache.get()); userMapper.selectSimple(str); assertEquals(new ProviderMethod().selectSimple(str), SqlCache.get()); } finally { SqlCache.remove(); sqlSession.close(); } } @Test public void testConcurrentExecution() throws InterruptedException { for (int i = 0; i < 10; i++) { new Thread(new Runnable() { @Override public void run() { try { Thread.sleep(100 * new Random().nextInt(10)); testInterceptor(); } catch (InterruptedException e) { e.printStackTrace(); } } }).start(); } Thread.currentThread().join(1500); } } ================================================ FILE: src/test/java/com/github/pagehelper/test/basic/sql/TestExists.java ================================================ /* * The MIT License (MIT) * * Copyright (c) 2014-2023 abel533@gmail.com * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ package com.github.pagehelper.test.basic.sql; import com.github.pagehelper.Page; import com.github.pagehelper.PageHelper; import com.github.pagehelper.mapper.UserMapper; import com.github.pagehelper.model.User; import com.github.pagehelper.util.MybatisHelper; import org.apache.ibatis.session.SqlSession; import org.junit.Test; import java.util.List; import static org.junit.Assert.assertEquals; public class TestExists { /** * union的count查询sql特殊 */ @Test public void testExists() { SqlSession sqlSession = MybatisHelper.getSqlSession(); UserMapper userMapper = sqlSession.getMapper(UserMapper.class); try { //获取第1页,10条内容,默认查询总数count PageHelper.startPage(1, 10); List list = userMapper.selectExists(); assertEquals(101, list.get(0).getId()); assertEquals(10, list.size()); assertEquals(83, ((Page) list).getTotal()); //获取第1页,10条内容,默认查询总数count PageHelper.startPage(2, 10); list = userMapper.selectExists(); assertEquals(111, list.get(0).getId()); assertEquals(10, list.size()); assertEquals(83, ((Page) list).getTotal()); } finally { sqlSession.close(); } } } ================================================ FILE: src/test/java/com/github/pagehelper/test/basic/sql/TestLeftjoin.java ================================================ /* * The MIT License (MIT) * * Copyright (c) 2014-2023 abel533@gmail.com * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ package com.github.pagehelper.test.basic.sql; import com.github.pagehelper.Page; import com.github.pagehelper.PageHelper; import com.github.pagehelper.mapper.UserMapper; import com.github.pagehelper.model.User; import com.github.pagehelper.util.MybatisHelper; import org.apache.ibatis.session.SqlSession; import org.junit.Test; import java.util.List; import static org.junit.Assert.assertEquals; public class TestLeftjoin { /** * left join的count查询sql特殊 */ @Test public void testLeftjoin() { SqlSession sqlSession = MybatisHelper.getSqlSession(); UserMapper userMapper = sqlSession.getMapper(UserMapper.class); try { //获取第1页,10条内容,默认查询总数count PageHelper.startPage(1, 10); List list = userMapper.selectLeftjoin(); assertEquals(1, list.get(0).getId()); assertEquals(10, list.size()); assertEquals(183, ((Page) list).getTotal()); //获取第1页,10条内容,默认查询总数count PageHelper.startPage(2, 10); list = userMapper.selectLeftjoin(); assertEquals(11, list.get(0).getId()); assertEquals(10, list.size()); assertEquals(183, ((Page) list).getTotal()); } finally { sqlSession.close(); } } } ================================================ FILE: src/test/java/com/github/pagehelper/test/basic/sql/TestUnion.java ================================================ /* * The MIT License (MIT) * * Copyright (c) 2014-2023 abel533@gmail.com * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ package com.github.pagehelper.test.basic.sql; import com.github.pagehelper.Page; import com.github.pagehelper.PageHelper; import com.github.pagehelper.mapper.UserMapper; import com.github.pagehelper.model.User; import com.github.pagehelper.util.MybatisHelper; import org.apache.ibatis.session.SqlSession; import org.junit.Test; import java.util.List; import static org.junit.Assert.assertEquals; public class TestUnion { /** * union的count查询sql特殊 */ @Test public void testUnion() { SqlSession sqlSession = MybatisHelper.getSqlSession(); UserMapper userMapper = sqlSession.getMapper(UserMapper.class); try { //获取第1页,10条内容,默认查询总数count PageHelper.startPage(1, 10); List list = userMapper.selectUnion(); assertEquals(1, list.get(0).getId()); assertEquals(10, list.size()); assertEquals(13, ((Page) list).getTotal()); //获取第1页,10条内容,默认查询总数count PageHelper.startPage(2, 10); list = userMapper.selectUnion(); assertEquals(181, list.get(0).getId()); assertEquals(3, list.size()); assertEquals(13, ((Page) list).getTotal()); } finally { sqlSession.close(); } } } ================================================ FILE: src/test/java/com/github/pagehelper/test/basic/sql/TestWith.java ================================================ /* * The MIT License (MIT) * * Copyright (c) 2014-2023 abel533@gmail.com * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ package com.github.pagehelper.test.basic.sql; import com.github.pagehelper.Page; import com.github.pagehelper.PageHelper; import com.github.pagehelper.mapper.UserMapper; import com.github.pagehelper.model.User; import com.github.pagehelper.util.MybatisHelper; import com.github.pagehelper.util.TestUtil; import org.apache.ibatis.session.SqlSession; import org.junit.Test; import java.util.List; import static org.junit.Assert.assertEquals; public class TestWith { /** * with的count查询sql特殊 - 只测试oracle,别的可能不支持 */ @Test public void testUnion() throws Exception { SqlSession sqlSession = MybatisHelper.getSqlSession(); UserMapper userMapper = sqlSession.getMapper(UserMapper.class); //只测试oracle if (!TestUtil.getXmlPath().equalsIgnoreCase("oracle")) { return; } try { //获取第1页,10条内容,默认查询总数count PageHelper.startPage(1, 10); List list = userMapper.selectWith(); assertEquals(151, list.get(0).getId()); assertEquals(10, list.size()); assertEquals(33, ((Page) list).getTotal()); //获取第1页,10条内容,默认查询总数count PageHelper.startPage(2, 10); list = userMapper.selectWith(); assertEquals(161, list.get(0).getId()); assertEquals(10, list.size()); assertEquals(33, ((Page) list).getTotal()); } finally { sqlSession.close(); } } } ================================================ FILE: src/test/java/com/github/pagehelper/test/features/autodialect/AutoDialectTest.java ================================================ /* * The MIT License (MIT) * * Copyright (c) 2014-2023 abel533@gmail.com * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ package com.github.pagehelper.test.features.autodialect; import com.github.pagehelper.PageHelper; import com.github.pagehelper.PageInfo; import com.github.pagehelper.PageSerializable; import com.github.pagehelper.mapper.UserMapper; import com.github.pagehelper.model.User; import com.github.pagehelper.util.MybatisAutoDialectHelper; import org.apache.ibatis.session.SqlSession; import org.junit.Test; import java.util.List; import static org.junit.Assert.assertEquals; public class AutoDialectTest { @Test public void test() { SqlSession sqlSession = MybatisAutoDialectHelper.getSqlSession(); UserMapper userMapper = sqlSession.getMapper(UserMapper.class); try { //获取第1页,10条内容,默认查询总数count PageHelper.startPage(1, 10); List list = userMapper.selectAll(); System.out.println(list); PageInfo page = new PageInfo(list); assertEquals(1, page.getPageNum()); assertEquals(10, page.getPageSize()); assertEquals(1, page.getStartRow()); assertEquals(10, page.getEndRow()); assertEquals(183, page.getTotal()); assertEquals(19, page.getPages()); assertEquals(true, page.isIsFirstPage()); assertEquals(false, page.isIsLastPage()); assertEquals(false, page.isHasPreviousPage()); assertEquals(true, page.isHasNextPage()); PageSerializable serializable = PageSerializable.of(list); assertEquals(183, serializable.getTotal()); //获取第2页,10条内容,默认查询总数count PageHelper.startPage(2, 10); list = userMapper.selectAll(); page = new PageInfo(list); assertEquals(2, page.getPageNum()); assertEquals(10, page.getPageSize()); assertEquals(11, page.getStartRow()); assertEquals(20, page.getEndRow()); assertEquals(183, page.getTotal()); assertEquals(19, page.getPages()); assertEquals(false, page.isIsFirstPage()); assertEquals(false, page.isIsLastPage()); assertEquals(true, page.isHasPreviousPage()); assertEquals(true, page.isHasNextPage()); //获取第19页,10条内容,默认查询总数count PageHelper.startPage(19, 10); list = userMapper.selectAll(); page = new PageInfo(list); assertEquals(19, page.getPageNum()); assertEquals(10, page.getPageSize()); assertEquals(181, page.getStartRow()); assertEquals(183, page.getEndRow()); assertEquals(183, page.getTotal()); assertEquals(19, page.getPages()); assertEquals(false, page.isIsFirstPage()); assertEquals(true, page.isIsLastPage()); assertEquals(true, page.isHasPreviousPage()); assertEquals(false, page.isHasNextPage()); } finally { sqlSession.close(); } } } ================================================ FILE: src/test/java/com/github/pagehelper/test/features/autodialect/DataSourceNegotiationAutoDialectTest.java ================================================ /* * The MIT License (MIT) * * Copyright (c) 2014-2023 abel533@gmail.com * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ package com.github.pagehelper.test.features.autodialect; import com.alibaba.druid.pool.DruidDataSource; import com.github.pagehelper.dialect.AbstractHelperDialect; import com.github.pagehelper.dialect.auto.DataSourceNegotiationAutoDialect; import com.github.pagehelper.dialect.auto.DruidAutoDialect; import com.github.pagehelper.dialect.helper.*; import com.mchange.v2.c3p0.ComboPooledDataSource; import com.zaxxer.hikari.HikariDataSource; import org.apache.commons.dbcp2.BasicDataSource; import org.apache.ibatis.datasource.unpooled.UnpooledDataSource; import org.junit.Assert; import org.junit.Test; import java.util.Properties; public class DataSourceNegotiationAutoDialectTest { public static final String HIKARI = "jdbc:h2:mem:basetest"; public static final String DRUID = "jdbc:herddb:mem:basetest"; public static final String TOMCAT = "jdbc:oracle://localhost/test"; public static final String C3P0 = "jdbc:mysql://localhost/test"; public static final String DBCP = "jdbc:postgresql://localhost/test"; public static final String DEFAULT = "jdbc:hsqldb:mem:basetest"; private HikariDataSource getHikari() { HikariDataSource dataSource = new HikariDataSource(); dataSource.setJdbcUrl(HIKARI); dataSource.setUsername("root"); dataSource.setPassword("password"); return dataSource; } private DruidDataSource getDriud() { DruidDataSource dataSource = new DruidDataSource(); dataSource.setUrl(DRUID); dataSource.setUsername("root"); dataSource.setPassword("password"); return dataSource; } private org.apache.tomcat.jdbc.pool.DataSource getTomcatJdbc() { org.apache.tomcat.jdbc.pool.DataSource dataSource = new org.apache.tomcat.jdbc.pool.DataSource(); dataSource.setUrl(TOMCAT); dataSource.setUsername("root"); dataSource.setPassword("password"); return dataSource; } private ComboPooledDataSource getC3P0() { ComboPooledDataSource dataSource = new ComboPooledDataSource(); dataSource.setJdbcUrl(C3P0); dataSource.setUser("root"); dataSource.setPassword("password"); return dataSource; } private BasicDataSource getDbcp() { BasicDataSource dataSource = new BasicDataSource(); dataSource.setUrl(DBCP); dataSource.setUsername("root"); dataSource.setPassword("password"); return dataSource; } private UnpooledDataSource getDefault() { UnpooledDataSource dataSource = new UnpooledDataSource(); dataSource.setUrl(DEFAULT); dataSource.setUsername("sa"); dataSource.setDriver("org.hsqldb.jdbcDriver"); return dataSource; } @Test public void testNegotiation() { Properties properties = new Properties(); properties.setProperty("closeConn", "true"); DataSourceNegotiationAutoDialect autoDialect = new DataSourceNegotiationAutoDialect(); String dialectKey = autoDialect.extractDialectKey(null, getHikari(), properties); Assert.assertEquals(HIKARI, dialectKey); AbstractHelperDialect dialect = autoDialect.extractDialect(dialectKey, null, getHikari(), properties); Assert.assertTrue(dialect instanceof HsqldbDialect); dialectKey = autoDialect.extractDialectKey(null, getDriud(), properties); Assert.assertEquals(DRUID, dialectKey); dialect = autoDialect.extractDialect(dialectKey, null, getDriud(), properties); Assert.assertTrue(dialect instanceof HerdDBDialect); dialectKey = autoDialect.extractDialectKey(null, getTomcatJdbc(), properties); Assert.assertEquals(TOMCAT, dialectKey); dialect = autoDialect.extractDialect(dialectKey, null, getTomcatJdbc(), properties); Assert.assertTrue(dialect instanceof OracleDialect); dialectKey = autoDialect.extractDialectKey(null, getC3P0(), properties); Assert.assertEquals(C3P0, dialectKey); dialect = autoDialect.extractDialect(dialectKey, null, getC3P0(), properties); Assert.assertTrue(dialect instanceof MySqlDialect); dialectKey = autoDialect.extractDialectKey(null, getDbcp(), properties); Assert.assertEquals(DBCP, dialectKey); dialect = autoDialect.extractDialect(dialectKey, null, getDbcp(), properties); Assert.assertTrue(dialect instanceof PostgreSqlDialect); dialectKey = autoDialect.extractDialectKey(null, getDefault(), properties); Assert.assertEquals(DEFAULT, dialectKey); dialect = autoDialect.extractDialect(dialectKey, null, getDefault(), properties); Assert.assertTrue(dialect instanceof HsqldbDialect); } @Test public void testDruid() { DruidAutoDialect druidAutoDialect = new DruidAutoDialect(); String jdbcUrl = druidAutoDialect.getJdbcUrl(getDriud()); Assert.assertEquals(DRUID, jdbcUrl); AbstractHelperDialect dialect = druidAutoDialect.extractDialect(jdbcUrl, null, null, new Properties()); Assert.assertTrue(dialect instanceof HerdDBDialect); } } ================================================ FILE: src/test/java/com/github/pagehelper/test/features/autodialect/SimpleAutoDialect.java ================================================ /* * The MIT License (MIT) * * Copyright (c) 2014-2023 abel533@gmail.com * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ package com.github.pagehelper.test.features.autodialect; import com.github.pagehelper.AutoDialect; import com.github.pagehelper.dialect.AbstractHelperDialect; import com.github.pagehelper.page.PageAutoDialect; import org.apache.ibatis.datasource.unpooled.UnpooledDataSource; import org.apache.ibatis.mapping.MappedStatement; import javax.sql.DataSource; import java.util.Properties; /** * 简单示例,直接从属性读取url,无需获取数据库连接,也不需要考虑是否需要关闭 */ public class SimpleAutoDialect implements AutoDialect { @Override public UnpooledDataSource extractDialectKey(MappedStatement ms, DataSource dataSource, Properties properties) { if (dataSource instanceof UnpooledDataSource) { return (UnpooledDataSource) dataSource; } throw new UnsupportedOperationException("不支持的数据源类型: " + dataSource.getClass().getName()); } @Override public AbstractHelperDialect extractDialect(UnpooledDataSource dialectKey, MappedStatement ms, DataSource dataSource, Properties properties) { String url = dialectKey.getUrl(); String dialect = PageAutoDialect.fromJdbcUrl(url); return PageAutoDialect.instanceDialect(dialect, properties); } } ================================================ FILE: src/test/java/com/github/pagehelper/test/features/dialectclass/UsingDialectClassTest.java ================================================ /* * The MIT License (MIT) * * Copyright (c) 2014-2023 abel533@gmail.com * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ package com.github.pagehelper.test.features.dialectclass; import com.github.pagehelper.Page; import com.github.pagehelper.PageHelper; import com.github.pagehelper.PageInfo; import com.github.pagehelper.PageSerializable; import com.github.pagehelper.dialect.AbstractHelperDialect; import com.github.pagehelper.mapper.UserMapper; import com.github.pagehelper.model.User; import com.github.pagehelper.page.PageAutoDialect; import com.github.pagehelper.util.MybatisHelper; import org.apache.ibatis.cache.CacheKey; import org.apache.ibatis.mapping.BoundSql; import org.apache.ibatis.mapping.MappedStatement; import org.apache.ibatis.session.SqlSession; import org.junit.Test; import java.util.List; import java.util.Map; import static org.junit.Assert.assertEquals; public class UsingDialectClassTest { public static final String TEST2_DIALECT_CLASS = Test2Dialect.class.getName(); static { //一个通过注册方法,另一个直接通过类名 PageAutoDialect.registerDialectAlias("test1", Test1Dialect.class); } @Test public void test() { SqlSession sqlSession = MybatisHelper.getSqlSession(); UserMapper userMapper = sqlSession.getMapper(UserMapper.class); try { //获取第1页,10条内容,默认查询总数count PageHelper.startPage(1, 10); List list = userMapper.selectAll(); System.out.println(list); PageInfo page = new PageInfo(list); assertEquals(1, page.getPageNum()); assertEquals(10, page.getPageSize()); assertEquals(1, page.getStartRow()); assertEquals(10, page.getEndRow()); assertEquals(183, page.getTotal()); assertEquals(19, page.getPages()); assertEquals(true, page.isIsFirstPage()); assertEquals(false, page.isIsLastPage()); assertEquals(false, page.isHasPreviousPage()); assertEquals(true, page.isHasNextPage()); PageSerializable serializable = PageSerializable.of(list); assertEquals(183, serializable.getTotal()); //获取第1页,10条内容,默认查询总数count PageHelper.startPage(1, 10).using("test1"); list = userMapper.selectAll(); page = new PageInfo(list); assertEquals(183, list.size()); assertEquals(183, page.getTotal()); serializable = PageSerializable.of(list); assertEquals(183, serializable.getTotal()); //获取第1页,10条内容,默认查询总数count PageHelper.startPage(1, 10); list = userMapper.selectAll(); page = new PageInfo(list); assertEquals(10, list.size()); assertEquals(183, page.getTotal()); serializable = PageSerializable.of(list); assertEquals(183, serializable.getTotal()); //获取第1页,10条内容,默认查询总数count PageHelper.startPage(2, 10); list = userMapper.selectAll(); page = new PageInfo(list); assertEquals(10, list.size()); assertEquals(183, page.getTotal()); serializable = PageSerializable.of(list); assertEquals(183, serializable.getTotal()); //获取第2页,10条内容,默认查询总数count PageHelper.startPage(2, 10).using(TEST2_DIALECT_CLASS); list = userMapper.selectAll(); page = new PageInfo(list); assertEquals(100, list.size()); assertEquals(183, page.getTotal()); PageHelper.startPage(3, 10); list = userMapper.selectAll(); page = new PageInfo(list); assertEquals(10, list.size()); assertEquals(183, page.getTotal()); } finally { sqlSession.close(); } } public static class Test1Dialect extends AbstractHelperDialect { @Override public Object processPageParameter(MappedStatement ms, Map paramMap, Page page, BoundSql boundSql, CacheKey pageKey) { return paramMap; } @Override public String getPageSql(String sql, Page page, CacheKey pageKey) { return "/*test1*/" + sql; } } public static class Test2Dialect extends AbstractHelperDialect { @Override public Object processPageParameter(MappedStatement ms, Map paramMap, Page page, BoundSql boundSql, CacheKey pageKey) { return paramMap; } @Override public String getPageSql(String sql, Page page, CacheKey pageKey) { pageKey.update(100); return "select * from (\n" + sql + "\n) temp_table where id <= 100"; } } } ================================================ FILE: src/test/java/com/github/pagehelper/test/namespace/BasicTest.java ================================================ /* * The MIT License (MIT) * * Copyright (c) 2014-2023 abel533@gmail.com * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ package com.github.pagehelper.test.namespace; import com.github.pagehelper.PageHelper; import com.github.pagehelper.model.User; import com.github.pagehelper.util.MybatisRowBoundsHelper; import org.apache.ibatis.session.RowBounds; import org.apache.ibatis.session.SqlSession; import org.junit.Test; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; import static org.junit.Assert.assertEquals; public class BasicTest { @Test public void testNamespace1() { SqlSession sqlSession = MybatisRowBoundsHelper.getSqlSession(); try { Map map = new HashMap(); User user = new User(); user.setName("刘睿"); map.put("user", user); //同时测试不可变Map map = Collections.unmodifiableMap(map); List list = sqlSession.selectList("select1", map, new RowBounds(1, 10)); assertEquals(1, list.size()); //判断查询结果的位置是否正确 assertEquals(78, list.get(0).getId()); } finally { sqlSession.close(); } } @Test public void testNamespace3() { SqlSession sqlSession = MybatisRowBoundsHelper.getSqlSession(); try { Map map = new HashMap(); User user = new User(); map.put("user", user); //同时测试不可变Map map = Collections.unmodifiableMap(map); List list = sqlSession.selectList("select1", map, new RowBounds(1, 10)); assertEquals(10, list.size()); //判断查询结果的位置是否正确 assertEquals(1, list.get(0).getId()); map = new HashMap(); user = new User(); user.setName("刘睿"); map.put("user", user); //同时测试不可变Map map = Collections.unmodifiableMap(map); list = sqlSession.selectList("select1", map, new RowBounds(1, 10)); assertEquals(1, list.size()); //判断查询结果的位置是否正确 assertEquals(78, list.get(0).getId()); } finally { sqlSession.close(); } } @Test public void testNamespace2() { SqlSession sqlSession = MybatisRowBoundsHelper.getSqlSession(); try { Map map = new HashMap(); User user = new User(); user.setName("刘睿"); map.put("user", user); PageHelper.startPage(1, 10); List list = sqlSession.selectList("select1", map); assertEquals(1, list.size()); //判断查询结果的位置是否正确 assertEquals(78, list.get(0).getId()); } finally { sqlSession.close(); } } } ================================================ FILE: src/test/java/com/github/pagehelper/test/pagesize/PageSizeLessThenOrEqualZeroTest.java ================================================ /* * The MIT License (MIT) * * Copyright (c) 2014-2023 abel533@gmail.com * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ package com.github.pagehelper.test.pagesize; import com.github.pagehelper.PageHelper; import com.github.pagehelper.PageInfo; import com.github.pagehelper.mapper.UserMapper; import com.github.pagehelper.model.User; import com.github.pagehelper.util.MybatisHelper; import org.apache.ibatis.session.RowBounds; import org.apache.ibatis.session.SqlSession; import org.junit.Test; import java.util.List; import static org.junit.Assert.assertEquals; public class PageSizeLessThenOrEqualZeroTest { /** * 使用Mapper接口调用时,使用PageHelper.startPage效果更好,不需要添加Mapper接口参数 */ @Test public void testWithStartPage() { SqlSession sqlSession = MybatisHelper.getSqlSession(); UserMapper userMapper = sqlSession.getMapper(UserMapper.class); try { //pageSize=0,这时候相当于用分页插件求count PageHelper.startPage(1, 0); List list = userMapper.selectAll(); PageInfo page = new PageInfo(list); assertEquals(0, list.size()); assertEquals(183, page.getTotal()); //limit<0的时候同上 PageHelper.startPage(1, -100); list = userMapper.selectAll(); page = new PageInfo(list); assertEquals(0, list.size()); assertEquals(183, page.getTotal()); } finally { sqlSession.close(); } } /** * 使用Mapper接口调用时,使用PageHelper.startPage效果更好,不需要添加Mapper接口参数 */ @Test public void testWithRowbounds() { //注意这里是MybatisRowBoundsHelper,会求count SqlSession sqlSession = MybatisHelper.getSqlSession(); UserMapper userMapper = sqlSession.getMapper(UserMapper.class); try { //limit=0,这时候相当于用分页插件求count,但是前提必须是配置rounbounds方式求count,否则都是-1 List list = userMapper.selectAll(new RowBounds(1, -1)); PageInfo page = new PageInfo(list); assertEquals(0, list.size()); assertEquals(183, page.getTotal()); //limit<0的时候同上 list = userMapper.selectAll(new RowBounds(1, -100)); page = new PageInfo(list); assertEquals(0, list.size()); assertEquals(183, page.getTotal()); } finally { sqlSession.close(); } } } ================================================ FILE: src/test/java/com/github/pagehelper/test/pagesize/PageSizeZeroTest.java ================================================ /* * The MIT License (MIT) * * Copyright (c) 2014-2023 abel533@gmail.com * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ package com.github.pagehelper.test.pagesize; import com.github.pagehelper.PageHelper; import com.github.pagehelper.PageInfo; import com.github.pagehelper.mapper.UserMapper; import com.github.pagehelper.model.User; import com.github.pagehelper.util.MybatisPageSizeZeroHelper; import org.apache.ibatis.session.RowBounds; import org.apache.ibatis.session.SqlSession; import org.junit.Test; import java.util.List; import static org.junit.Assert.assertEquals; /** * @author liuzh */ public class PageSizeZeroTest { /** * 使用Mapper接口调用时,使用PageHelper.startPage效果更好,不需要添加Mapper接口参数 */ @Test public void testWithStartPage() { SqlSession sqlSession = MybatisPageSizeZeroHelper.getSqlSession(); UserMapper userMapper = sqlSession.getMapper(UserMapper.class); try { //pageSize=0的时候查询全部结果 PageHelper.startPage(1, 0); List list = userMapper.selectAll(); PageInfo page = new PageInfo(list); assertEquals(183, list.size()); assertEquals(183, page.getTotal()); //pageSize=0的时候查询全部结果 PageHelper.startPage(10, 0); list = userMapper.selectAll(); page = new PageInfo(list); assertEquals(183, list.size()); assertEquals(183, page.getTotal()); } finally { sqlSession.close(); } } /** * 使用Mapper接口调用时,使用PageHelper.startPage效果更好,不需要添加Mapper接口参数 */ @Test public void testWithRowbounds() { SqlSession sqlSession = MybatisPageSizeZeroHelper.getSqlSession(); UserMapper userMapper = sqlSession.getMapper(UserMapper.class); try { //pageSize=0的时候查询全部结果 List list = userMapper.selectAll(new RowBounds(1, 0)); PageInfo page = new PageInfo(list); assertEquals(183, list.size()); assertEquals(183, page.getTotal()); //pageSize=0的时候查询全部结果 PageHelper.startPage(10, 0); list = userMapper.selectAll(new RowBounds(1000, 0)); page = new PageInfo(list); assertEquals(183, list.size()); assertEquals(183, page.getTotal()); } finally { sqlSession.close(); } } } ================================================ FILE: src/test/java/com/github/pagehelper/test/reasonable/PageTest.java ================================================ /* * The MIT License (MIT) * * Copyright (c) 2014-2023 abel533@gmail.com * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ package com.github.pagehelper.test.reasonable; import com.github.pagehelper.PageHelper; import com.github.pagehelper.PageInfo; import com.github.pagehelper.mapper.UserMapper; import com.github.pagehelper.model.User; import com.github.pagehelper.util.MybatisReasonableHelper; import org.apache.ibatis.session.SqlSession; import org.junit.Test; import java.util.List; import static org.junit.Assert.assertEquals; public class PageTest { /** * 使用Mapper接口调用时,使用PageHelper.startPage效果更好,不需要添加Mapper接口参数 */ @Test public void testMapperWithStartPage() { SqlSession sqlSession = MybatisReasonableHelper.getSqlSession(); UserMapper userMapper = sqlSession.getMapper(UserMapper.class); try { //获取第20页,2条内容 //分页插件会自动改为查询最后一页 PageHelper.startPage(20, 50); List list = userMapper.selectAll(); PageInfo page = new PageInfo(list); assertEquals(33, list.size()); assertEquals(151, page.getStartRow()); assertEquals(4, page.getPageNum()); assertEquals(183, page.getTotal()); //获取第-3页,2条内容 //由于只有7天数据,分页插件会自动改为查询最后一页 PageHelper.startPage(-3, 50); list = userMapper.selectAll(); page = new PageInfo(list); assertEquals(50, list.size()); assertEquals(1, page.getStartRow()); assertEquals(1, page.getPageNum()); assertEquals(183, page.getTotal()); } finally { sqlSession.close(); } } @Test public void testMapperWithStartPageAndReasonableFalse() { SqlSession sqlSession = MybatisReasonableHelper.getSqlSession(); UserMapper userMapper = sqlSession.getMapper(UserMapper.class); try { //获取第20页,2条内容 //分页插件会自动改为查询最后一页 PageHelper.startPage(20, 50, true, false, false); List list = userMapper.selectAll(); PageInfo page = new PageInfo(list); assertEquals(0, list.size()); assertEquals(0, page.getStartRow()); assertEquals(20, page.getPageNum()); assertEquals(183, page.getTotal()); PageHelper.startPage(4, 50, true, false, false); list = userMapper.selectAll(); page = new PageInfo(list); assertEquals(33, list.size()); assertEquals(151, page.getStartRow()); assertEquals(4, page.getPageNum()); assertEquals(183, page.getTotal()); PageHelper.startPage(-1, 50, true, false, false); list = userMapper.selectAll(); page = new PageInfo(list); assertEquals(0, list.size()); assertEquals(0, page.getStartRow()); assertEquals(-1, page.getPageNum()); assertEquals(183, page.getTotal()); } finally { sqlSession.close(); } } @Test public void testMapperWithStartPageAndReasonableTrue() { SqlSession sqlSession = MybatisReasonableHelper.getSqlSession(); UserMapper userMapper = sqlSession.getMapper(UserMapper.class); try { //获取第20页,2条内容 //分页插件会自动改为查询最后一页 PageHelper.startPage(20, 50, true, true, false); List list = userMapper.selectAll(); PageInfo page = new PageInfo(list); assertEquals(33, list.size()); assertEquals(151, page.getStartRow()); assertEquals(4, page.getPageNum()); assertEquals(183, page.getTotal()); PageHelper.startPage(4, 50, true, true, false); list = userMapper.selectAll(); page = new PageInfo(list); assertEquals(33, list.size()); assertEquals(151, page.getStartRow()); assertEquals(4, page.getPageNum()); assertEquals(183, page.getTotal()); PageHelper.startPage(-1, 50, true, true, false); list = userMapper.selectAll(); page = new PageInfo(list); assertEquals(50, list.size()); assertEquals(1, page.getStartRow()); assertEquals(1, page.getPageNum()); assertEquals(183, page.getTotal()); } finally { sqlSession.close(); } } @Test public void testMapperWithStartPageAndPageSizeZeroFalse() { SqlSession sqlSession = MybatisReasonableHelper.getSqlSession(); UserMapper userMapper = sqlSession.getMapper(UserMapper.class); try { //获取第20页,2条内容 //分页插件会自动改为查询最后一页 PageHelper.startPage(1, 0, true, true, false); List list = userMapper.selectAll(); PageInfo page = new PageInfo(list); assertEquals(0, list.size()); assertEquals(0, page.getStartRow()); assertEquals(1, page.getPageNum()); assertEquals(183, page.getTotal()); PageHelper.startPage(1, Integer.MAX_VALUE, true, true, false); list = userMapper.selectAll(); page = new PageInfo(list); assertEquals(183, list.size()); assertEquals(1, page.getStartRow()); assertEquals(1, page.getPageNum()); assertEquals(183, page.getTotal()); } finally { sqlSession.close(); } } @Test public void testMapperWithStartPageAndPageSizeZeroTrue() { SqlSession sqlSession = MybatisReasonableHelper.getSqlSession(); UserMapper userMapper = sqlSession.getMapper(UserMapper.class); try { //获取第20页,2条内容 //分页插件会自动改为查询最后一页 PageHelper.startPage(1, 0, true, true, true); List list = userMapper.selectAll(); PageInfo page = new PageInfo(list); assertEquals(183, list.size()); assertEquals(1, page.getStartRow()); assertEquals(1, page.getPageNum()); assertEquals(183, page.getTotal()); PageHelper.startPage(1, -1, true, true, true); list = userMapper.selectAll(); page = new PageInfo(list); assertEquals(0, list.size()); assertEquals(0, page.getStartRow()); assertEquals(1, page.getPageNum()); assertEquals(183, page.getTotal()); } finally { sqlSession.close(); } } } ================================================ FILE: src/test/java/com/github/pagehelper/test/rowbounds/RowBoundsTest.java ================================================ /* * The MIT License (MIT) * * Copyright (c) 2014-2023 abel533@gmail.com * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ package com.github.pagehelper.test.rowbounds; import com.github.pagehelper.Page; import com.github.pagehelper.PageHelper; import com.github.pagehelper.PageInfo; import com.github.pagehelper.mapper.UserMapper; import com.github.pagehelper.model.User; import com.github.pagehelper.util.MybatisRowBoundsHelper; import org.apache.ibatis.session.RowBounds; import org.apache.ibatis.session.SqlSession; import org.junit.Test; import java.util.HashMap; import java.util.List; import java.util.Map; import static org.junit.Assert.assertEquals; public class RowBoundsTest { /** * 使用Mapper接口调用时,对接口增加RowBounds参数,不需要修改对应的xml配置(或注解配置) *

* RowBounds方式不进行count查询,可以通过修改Page代码实现 *

* 这种情况下如果同时使用startPage方法,以startPage为准 */ @Test public void testMapperWithRowBounds() { SqlSession sqlSession = MybatisRowBoundsHelper.getSqlSession(); UserMapper userMapper = sqlSession.getMapper(UserMapper.class); try { //获取第1页,10条内容,默认查询总数count List list = userMapper.selectAll(new RowBounds(1, 10)); //新增PageInfo对象,对返回结果进行封装 PageInfo page = new PageInfo(list); assertEquals(10, list.size()); assertEquals(183, page.getTotal()); //判断查询结果的位置是否正确 assertEquals(1, list.get(0).getId()); assertEquals(10, list.get(list.size() - 1).getId()); //获取第10页,10条内容,显式查询总数count list = userMapper.selectAll(new RowBounds(10, 10)); assertEquals(10, list.size()); assertEquals(183, ((Page) list).getTotal()); //判断查询结果的位置是否正确 assertEquals(91, list.get(0).getId()); assertEquals(100, list.get(list.size() - 1).getId()); //获取第3页,20条内容,默认查询总数count list = userMapper.selectAll(new RowBounds(6, 20)); assertEquals(20, list.size()); assertEquals(183, ((Page) list).getTotal()); //判断查询结果的位置是否正确 assertEquals(101, list.get(0).getId()); assertEquals(120, list.get(list.size() - 1).getId()); } finally { sqlSession.close(); } } /** * 使用命名空间方式的RowBounds进行分页,使用RowBounds时不进行count查询 * 通过修改代码可以进行count查询,没法通过其他方法改变参数 * 因为如果通过调用一个别的方法来标记count查询,还不如直接startPage *

* 同时使用startPage时,以startPage为准,会根据startPage参数来查询 */ @Test public void testNamespaceWithRowBounds() { SqlSession sqlSession = MybatisRowBoundsHelper.getSqlSession(); try { //获取从0开始,10条内容 List list = sqlSession.selectList("selectAll", null, new RowBounds(1, 10)); assertEquals(10, list.size()); assertEquals(183, ((Page) list).getTotal()); //判断查询结果的位置是否正确 assertEquals(1, list.get(0).getId()); assertEquals(10, list.get(list.size() - 1).getId()); //获取从10开始,10条内容 list = sqlSession.selectList("selectAll", null, new RowBounds(10, 10)); assertEquals(10, list.size()); assertEquals(183, ((Page) list).getTotal()); //判断查询结果的位置是否正确 assertEquals(91, list.get(0).getId()); assertEquals(100, list.get(list.size() - 1).getId()); //获取从20开始,20条内容 list = sqlSession.selectList("selectAll", null, new RowBounds(6, 20)); assertEquals(20, list.size()); assertEquals(183, ((Page) list).getTotal()); //判断查询结果的位置是否正确 assertEquals(101, list.get(0).getId()); assertEquals(120, list.get(list.size() - 1).getId()); } finally { sqlSession.close(); } } @Test public void testNamespaceWithRowBounds2() { SqlSession sqlSession = MybatisRowBoundsHelper.getSqlSession(); try { //获取从0开始,10条内容 List list = sqlSession.selectList("selectIf", null, new RowBounds(1, 10)); assertEquals(10, list.size()); assertEquals(183, ((Page) list).getTotal()); //判断查询结果的位置是否正确 assertEquals(1, list.get(0).getId()); assertEquals(10, list.get(list.size() - 1).getId()); Map map = new HashMap(); map.put("id", 10); //获取从10开始,10条内容 list = sqlSession.selectList("selectIf", map, new RowBounds(10, 10)); assertEquals(10, list.size()); assertEquals(173, ((Page) list).getTotal()); //判断查询结果的位置是否正确 assertEquals(101, list.get(0).getId()); assertEquals(110, list.get(list.size() - 1).getId()); } finally { sqlSession.close(); } } @Test public void testNamespaceWithRowBounds3() { SqlSession sqlSession = MybatisRowBoundsHelper.getSqlSession(); try { //获取从0开始,10条内容 PageHelper.startPage(1, 10); List list = sqlSession.selectList("selectIf", null); assertEquals(10, list.size()); assertEquals(183, ((Page) list).getTotal()); //判断查询结果的位置是否正确 assertEquals(1, list.get(0).getId()); assertEquals(10, list.get(list.size() - 1).getId()); Map map = new HashMap(); map.put("id", 10); //获取从10开始,10条内容 PageHelper.startPage(10, 10); list = sqlSession.selectList("selectIf", map); assertEquals(10, list.size()); assertEquals(173, ((Page) list).getTotal()); //判断查询结果的位置是否正确 assertEquals(101, list.get(0).getId()); assertEquals(110, list.get(list.size() - 1).getId()); IdBean user = new IdBean(); //获取从10开始,10条内容 PageHelper.startPage(10, 10); list = sqlSession.selectList("selectIf", user); assertEquals(10, list.size()); assertEquals(183, ((Page) list).getTotal()); //判断查询结果的位置是否正确 assertEquals(91, list.get(0).getId()); assertEquals(100, list.get(list.size() - 1).getId()); } finally { sqlSession.close(); } } /** * 使用Mapper接口调用时,使用PageHelper.startPage效果更好,不需要添加Mapper接口参数 */ @Test public void testWithRowboundsAndCountTrue() { SqlSession sqlSession = MybatisRowBoundsHelper.getSqlSession(); UserMapper userMapper = sqlSession.getMapper(UserMapper.class); try { //limit=0,这时候相当于用分页插件求count,但是前提必须是配置rounbounds方式求count,否则都是-1 //这里由于没有配置,应该都是-1 List list = userMapper.selectAll(new RowBounds(1, -1)); PageInfo page = new PageInfo(list); assertEquals(0, list.size()); assertEquals(183, page.getTotal()); //pageSize<0的时候同上 list = userMapper.selectAll(new RowBounds(1, -100)); page = new PageInfo(list); assertEquals(0, list.size()); assertEquals(183, page.getTotal()); } finally { sqlSession.close(); } } class IdBean { private Integer id; public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } } } ================================================ FILE: src/test/java/com/github/pagehelper/util/MybatisAutoDialectHelper.java ================================================ /* * The MIT License (MIT) * * Copyright (c) 2014-2023 abel533@gmail.com * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ package com.github.pagehelper.util; import org.apache.ibatis.io.Resources; import org.apache.ibatis.jdbc.ScriptRunner; import org.apache.ibatis.session.SqlSession; import org.apache.ibatis.session.SqlSessionFactory; import org.apache.ibatis.session.SqlSessionFactoryBuilder; import java.io.IOException; import java.io.Reader; import java.sql.Connection; /** * Description: MybatisHelper * Author: liuzh * Update: liuzh(2014-06-06 13:33) */ public class MybatisAutoDialectHelper { private static SqlSessionFactory sqlSessionFactory; static { try { //创建SqlSessionFactory Reader reader = Resources.getResourceAsReader(TestUtil.getXmlPath() + "/mybatis-config-autodialect.xml"); sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader); reader.close(); if (TestUtil.getXmlPath().equalsIgnoreCase("hsqldb") || TestUtil.getXmlPath().equalsIgnoreCase("h2") || TestUtil.getXmlPath().equalsIgnoreCase("derby")) { //创建数据库 SqlSession session = null; try { session = sqlSessionFactory.openSession(); Connection conn = session.getConnection(); reader = Resources.getResourceAsReader(TestUtil.getXmlPath() + "/" + TestUtil.getXmlPath() + ".sql"); ScriptRunner runner = new ScriptRunner(conn); runner.setLogWriter(null); runner.runScript(reader); reader.close(); } finally { if (session != null) { session.close(); } } } } catch (IOException e) { e.printStackTrace(); } } /** * 获取Session * * @return */ public static SqlSession getSqlSession() { return sqlSessionFactory.openSession(); } } ================================================ FILE: src/test/java/com/github/pagehelper/util/MybatisHelper.java ================================================ /* * The MIT License (MIT) * * Copyright (c) 2014-2023 abel533@gmail.com * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ package com.github.pagehelper.util; import com.github.pagehelper.dialect.auto.DataSourceAutoDialect; import com.github.pagehelper.dialect.auto.DataSourceNegotiationAutoDialect; import org.apache.ibatis.datasource.unpooled.UnpooledDataSource; import org.apache.ibatis.io.Resources; import org.apache.ibatis.jdbc.ScriptRunner; import org.apache.ibatis.session.SqlSession; import org.apache.ibatis.session.SqlSessionFactory; import org.apache.ibatis.session.SqlSessionFactoryBuilder; import java.io.IOException; import java.io.Reader; import java.sql.Connection; /** * Description: MybatisHelper * Author: liuzh * Update: liuzh(2014-06-06 13:33) */ public class MybatisHelper { private static SqlSessionFactory sqlSessionFactory; static { try { //创建SqlSessionFactory Reader reader = Resources.getResourceAsReader(TestUtil.getXmlPath() + "/mybatis-config.xml"); sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader); reader.close(); if (TestUtil.getXmlPath().equalsIgnoreCase("hsqldb") || TestUtil.getXmlPath().equalsIgnoreCase("h2") || TestUtil.getXmlPath().equalsIgnoreCase("derby")) { //创建数据库 SqlSession session = null; try { session = sqlSessionFactory.openSession(); Connection conn = session.getConnection(); reader = Resources.getResourceAsReader(TestUtil.getXmlPath() + "/" + TestUtil.getXmlPath() + ".sql"); ScriptRunner runner = new ScriptRunner(conn); runner.setLogWriter(null); runner.runScript(reader); reader.close(); } finally { if (session != null) { session.close(); } } } } catch (IOException e) { e.printStackTrace(); } //添加一个针对 unpool 的 AutoDialect DataSourceNegotiationAutoDialect.registerAutoDialect(new DataSourceAutoDialect() { @Override public String getJdbcUrl(UnpooledDataSource unpooledDataSource) { return unpooledDataSource.getUrl(); } }); } /** * 获取Session * * @return */ public static SqlSession getSqlSession() { return sqlSessionFactory.openSession(); } } ================================================ FILE: src/test/java/com/github/pagehelper/util/MybatisInterceptorHelper.java ================================================ /* * The MIT License (MIT) * * Copyright (c) 2014-2023 abel533@gmail.com * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ package com.github.pagehelper.util; import org.apache.ibatis.io.Resources; import org.apache.ibatis.jdbc.ScriptRunner; import org.apache.ibatis.session.SqlSession; import org.apache.ibatis.session.SqlSessionFactory; import org.apache.ibatis.session.SqlSessionFactoryBuilder; import java.io.IOException; import java.io.Reader; import java.sql.Connection; /** * Description: MybatisHelper * Author: liuzh * Update: liuzh(2014-06-06 13:33) */ public class MybatisInterceptorHelper { private static SqlSessionFactory sqlSessionFactory; static { try { //创建SqlSessionFactory Reader reader = Resources.getResourceAsReader(TestUtil.getXmlPath() + "/mybatis-config-interceptor.xml"); sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader); reader.close(); if (TestUtil.getXmlPath().equalsIgnoreCase("hsqldb") || TestUtil.getXmlPath().equalsIgnoreCase("h2") || TestUtil.getXmlPath().equalsIgnoreCase("derby")) { //创建数据库 SqlSession session = null; try { session = sqlSessionFactory.openSession(); Connection conn = session.getConnection(); reader = Resources.getResourceAsReader(TestUtil.getXmlPath() + "/" + TestUtil.getXmlPath() + ".sql"); ScriptRunner runner = new ScriptRunner(conn); runner.setLogWriter(null); runner.runScript(reader); reader.close(); } finally { if (session != null) { session.close(); } } } } catch (IOException e) { e.printStackTrace(); } } /** * 获取Session * * @return */ public static SqlSession getSqlSession() { return sqlSessionFactory.openSession(); } } ================================================ FILE: src/test/java/com/github/pagehelper/util/MybatisPageSizeZeroHelper.java ================================================ /* * The MIT License (MIT) * * Copyright (c) 2014-2023 abel533@gmail.com * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ package com.github.pagehelper.util; import org.apache.ibatis.io.Resources; import org.apache.ibatis.jdbc.ScriptRunner; import org.apache.ibatis.session.SqlSession; import org.apache.ibatis.session.SqlSessionFactory; import org.apache.ibatis.session.SqlSessionFactoryBuilder; import java.io.IOException; import java.io.Reader; import java.sql.Connection; /** * Description: MybatisHelper * Author: liuzh * Update: liuzh(2014-06-06 13:33) */ public class MybatisPageSizeZeroHelper { private static SqlSessionFactory sqlSessionFactory; static { try { //创建SqlSessionFactory Reader reader = Resources.getResourceAsReader(TestUtil.getXmlPath() + "/mybatis-config-pagesizezero.xml"); sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader); reader.close(); if (TestUtil.getXmlPath().equalsIgnoreCase("hsqldb") || TestUtil.getXmlPath().equalsIgnoreCase("h2") || TestUtil.getXmlPath().equalsIgnoreCase("derby")) { //创建数据库 SqlSession session = null; try { session = sqlSessionFactory.openSession(); Connection conn = session.getConnection(); reader = Resources.getResourceAsReader(TestUtil.getXmlPath() + "/" + TestUtil.getXmlPath() + ".sql"); ScriptRunner runner = new ScriptRunner(conn); runner.setLogWriter(null); runner.runScript(reader); reader.close(); } finally { if (session != null) { session.close(); } } } } catch (IOException e) { e.printStackTrace(); } } /** * 获取Session * * @return */ public static SqlSession getSqlSession() { return sqlSessionFactory.openSession(); } } ================================================ FILE: src/test/java/com/github/pagehelper/util/MybatisReasonableHelper.java ================================================ /* * The MIT License (MIT) * * Copyright (c) 2014-2023 abel533@gmail.com * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ package com.github.pagehelper.util; import org.apache.ibatis.io.Resources; import org.apache.ibatis.jdbc.ScriptRunner; import org.apache.ibatis.session.SqlSession; import org.apache.ibatis.session.SqlSessionFactory; import org.apache.ibatis.session.SqlSessionFactoryBuilder; import java.io.IOException; import java.io.Reader; import java.sql.Connection; /** * Description: MybatisHelper * Author: liuzh * Update: liuzh(2014-06-06 13:33) */ public class MybatisReasonableHelper { private static SqlSessionFactory sqlSessionFactory; static { try { //创建SqlSessionFactory Reader reader = Resources.getResourceAsReader(TestUtil.getXmlPath() + "/mybatis-config-reasonable.xml"); sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader); reader.close(); if (TestUtil.getXmlPath().equalsIgnoreCase("hsqldb") || TestUtil.getXmlPath().equalsIgnoreCase("h2") || TestUtil.getXmlPath().equalsIgnoreCase("derby")) { //创建数据库 SqlSession session = null; try { session = sqlSessionFactory.openSession(); Connection conn = session.getConnection(); reader = Resources.getResourceAsReader(TestUtil.getXmlPath() + "/" + TestUtil.getXmlPath() + ".sql"); ScriptRunner runner = new ScriptRunner(conn); runner.setLogWriter(null); runner.runScript(reader); reader.close(); } finally { if (session != null) { session.close(); } } } } catch (IOException e) { e.printStackTrace(); } } /** * 获取Session * * @return */ public static SqlSession getSqlSession() { return sqlSessionFactory.openSession(); } } ================================================ FILE: src/test/java/com/github/pagehelper/util/MybatisRowBoundsHelper.java ================================================ /* * The MIT License (MIT) * * Copyright (c) 2014-2023 abel533@gmail.com * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ package com.github.pagehelper.util; import org.apache.ibatis.io.Resources; import org.apache.ibatis.jdbc.ScriptRunner; import org.apache.ibatis.session.SqlSession; import org.apache.ibatis.session.SqlSessionFactory; import org.apache.ibatis.session.SqlSessionFactoryBuilder; import java.io.IOException; import java.io.Reader; import java.sql.Connection; /** * Description: MybatisHelper * Author: liuzh * Update: liuzh(2014-06-06 13:33) */ public class MybatisRowBoundsHelper { private static SqlSessionFactory sqlSessionFactory; static { try { //创建SqlSessionFactory Reader reader = Resources.getResourceAsReader(TestUtil.getXmlPath() + "/mybatis-config-rowbounds.xml"); sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader); reader.close(); if (TestUtil.getXmlPath().equalsIgnoreCase("hsqldb") || TestUtil.getXmlPath().equalsIgnoreCase("h2") || TestUtil.getXmlPath().equalsIgnoreCase("derby")) { //创建数据库 SqlSession session = null; try { session = sqlSessionFactory.openSession(); Connection conn = session.getConnection(); reader = Resources.getResourceAsReader(TestUtil.getXmlPath() + "/" + TestUtil.getXmlPath() + ".sql"); ScriptRunner runner = new ScriptRunner(conn); runner.setLogWriter(null); runner.runScript(reader); reader.close(); } finally { if (session != null) { session.close(); } } } } catch (IOException e) { e.printStackTrace(); } } /** * 获取Session * * @return */ public static SqlSession getSqlSession() { return sqlSessionFactory.openSession(); } } ================================================ FILE: src/test/java/com/github/pagehelper/util/Ognl.java ================================================ /* * The MIT License (MIT) * * Copyright (c) 2014-2023 abel533@gmail.com * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ package com.github.pagehelper.util;/** * @author liuzh */ public class Ognl { public static boolean isNotNull(Object obj) { return obj != null; } } ================================================ FILE: src/test/java/com/github/pagehelper/util/SqlSafeUtilTest.java ================================================ /* * The MIT License (MIT) * * Copyright (c) 2014-2023 abel533@gmail.com * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ package com.github.pagehelper.util; import org.junit.Test; import static org.junit.Assert.assertEquals; public class SqlSafeUtilTest { @Test public void check() { assertSql(true, "insert into xx"); // 无空格 assertSql(false, "insertxxinto xx"); assertSql(false, "insert_into"); assertSql(true, "SELECT aa FROM user"); // 无空格 assertSql(true, "SELECT*FROM user"); // 左空格 assertSql(true, "SELECT *FROM user"); // 右空格 assertSql(true, "SELECT* FROM user"); // 左tab assertSql(true, "SELECT *FROM user"); // 右tab assertSql(true, "SELECT* FROM user"); assertSql(false, "SELECT*FROMuser"); // 验证 issue #707 问题 assertSql(false, "databaseType desc,orderNum desc"); } private void assertSql(boolean injection, String sql) { assertEquals(injection, SqlSafeUtil.check(sql)); } } ================================================ FILE: src/test/java/com/github/pagehelper/util/TestUtil.java ================================================ /* * The MIT License (MIT) * * Copyright (c) 2014-2023 abel533@gmail.com * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ package com.github.pagehelper.util; import java.io.IOException; import java.io.InputStream; import java.util.Properties; /** * @author liuzh */ public class TestUtil { public static String XML_PATH; public synchronized static String getXmlPath() throws IOException { if (XML_PATH != null) { return XML_PATH; } Properties properties = new Properties(); InputStream is = null; try { is = TestUtil.class.getResourceAsStream("/test.properties"); properties.load(is); XML_PATH = properties.getProperty("database"); } finally { if (is != null) { is.close(); } } return XML_PATH; } } ================================================ FILE: src/test/resources/cirrodata/cirrodata.sql ================================================ /* * The MIT License (MIT) * * Copyright (c) 2014-2022 abel533@gmail.com * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ CREATE DATABASE `pagehelper` CHARACTER SET 'UTF-8'; CREATE USER TEST_USER identified by '123456_' DROP TABLE `user`; CREATE TABLE `user` ( `id` int(11), `name` varchar(50) DEFAULT NULL, `py` varchar(50) DEFAULT NULL ); insert into user(id, name, py) values('1','毕淑儒','BSR'); insert into user(id, name, py) values('2','蔡兴熙','CXX'); insert into user(id, name, py) values('3','曾三杰','ZSJ'); insert into user(id, name, py) values('4','常元琴','CYQ'); insert into user(id, name, py) values('5','陈栋芬','CDF'); insert into user(id, name, py) values('6','陈宁婷','CNZ'); insert into user(id, name, py) values('7','陈瑞','CR'); insert into user(id, name, py) values('8','陈武宵','CWX'); insert into user(id, name, py) values('9','陈晓丽','CXL'); insert into user(id, name, py) values('10','陈翼涛','CYT'); insert into user(id, name, py) values('11','陈宇然','CYR'); insert into user(id, name, py) values('12','陈震','CZ'); insert into user(id, name, py) values('13','程太君','CTJ'); insert into user(id, name, py) values('14','程玉娜','CYN'); insert into user(id, name, py) values('15','丛贺轩','CHX'); insert into user(id, name, py) values('16','戴国宇','DGY'); insert into user(id, name, py) values('17','戴杰亮','DJL'); insert into user(id, name, py) values('18','丁玉华','DYH'); insert into user(id, name, py) values('19','董秋明','DQM'); insert into user(id, name, py) values('20','董政厚','DZH'); insert into user(id, name, py) values('21','杜玉焱','DYZ'); insert into user(id, name, py) values('22','段瑜芝','DZZ'); insert into user(id, name, py) values('23','傅广友','FGY'); insert into user(id, name, py) values('24','傅井飞','FJF'); insert into user(id, name, py) values('25','高辉涛','GHT'); insert into user(id, name, py) values('26','高龙飞','GLF'); insert into user(id, name, py) values('27','高汝英','GRY'); insert into user(id, name, py) values('28','高云天','GYT'); insert into user(id, name, py) values('29','郭义民','GYM'); insert into user(id, name, py) values('30','郭永洪','GYH'); insert into user(id, name, py) values('31','韩国茜','HGZ'); insert into user(id, name, py) values('32','韩龙康','HLK'); insert into user(id, name, py) values('33','韩伟佳','HWJ'); insert into user(id, name, py) values('34','韩扬谦','HYQ'); insert into user(id, name, py) values('35','郝静生','HJS'); insert into user(id, name, py) values('36','何柏红','HBH'); insert into user(id, name, py) values('37','何彩智','HCZ'); insert into user(id, name, py) values('38','何陶增','HTZ'); insert into user(id, name, py) values('39','何薇','HZ'); insert into user(id, name, py) values('40','何小凡','HXF'); insert into user(id, name, py) values('41','何振平','HZP'); insert into user(id, name, py) values('42','洪彩辉','HCH'); insert into user(id, name, py) values('43','胡仕明','HSM'); insert into user(id, name, py) values('44','黄建朋','HJP'); insert into user(id, name, py) values('45','黄祥荣','HXR'); insert into user(id, name, py) values('46','黄璇平','HZP'); insert into user(id, name, py) values('47','贾茂飞','JMF'); insert into user(id, name, py) values('48','李迪茹','LDR'); insert into user(id, name, py) values('49','李桂博','LGB'); insert into user(id, name, py) values('50','李国祯','LGZ'); insert into user(id, name, py) values('51','李宏川','LHC'); insert into user(id, name, py) values('52','李梅','LM'); insert into user(id, name, py) values('53','李媚文','LMW'); insert into user(id, name, py) values('54','李孟惠','LMH'); insert into user(id, name, py) values('55','李南懋','LNZ'); insert into user(id, name, py) values('56','李鹏龙','LPL'); insert into user(id, name, py) values('57','李诗庸','LSY'); insert into user(id, name, py) values('58','李姝勇','LZY'); insert into user(id, name, py) values('59','李树鹏','LSP'); insert into user(id, name, py) values('60','李薇红','LZH'); insert into user(id, name, py) values('61','李文章','LWZ'); insert into user(id, name, py) values('62','李星佳','LXJ'); insert into user(id, name, py) values('63','李兴','LX'); insert into user(id, name, py) values('64','李秀倩','LXZ'); insert into user(id, name, py) values('65','李艳生','LYS'); insert into user(id, name, py) values('66','李燕金','LYJ'); insert into user(id, name, py) values('67','李玉彪','LYB'); insert into user(id, name, py) values('68','李振峰','LZF'); insert into user(id, name, py) values('69','梁斌芳','LBF'); insert into user(id, name, py) values('70','梁国云','LGY'); insert into user(id, name, py) values('71','梁巧爱','LQA'); insert into user(id, name, py) values('72','梁照金','LZJ'); insert into user(id, name, py) values('73','林婧美','LZM'); insert into user(id, name, py) values('74','林沛寿','LPS'); insert into user(id, name, py) values('75','林薇程','LZC'); insert into user(id, name, py) values('76','林伟玉','LWY'); insert into user(id, name, py) values('77','林艺玲','LYL'); insert into user(id, name, py) values('78','刘睿','LR'); insert into user(id, name, py) values('79','刘芊芊','LQQ'); insert into user(id, name, py) values('80','刘海波','LHB'); insert into user(id, name, py) values('81','刘斓琴','LZQ'); insert into user(id, name, py) values('82','刘磊东','LLD'); insert into user(id, name, py) values('83','刘明琪','LMZ'); insert into user(id, name, py) values('84','刘铭恩','LME'); insert into user(id, name, py) values('85','刘任恺','LRZ'); insert into user(id, name, py) values('86','刘水秋','LSQ'); insert into user(id, name, py) values('87','刘文萱','LWZ'); insert into user(id, name, py) values('88','刘祥瑶','LXY'); insert into user(id, name, py) values('89','刘薪坪','LXP'); insert into user(id, name, py) values('90','刘秀涛','LXT'); insert into user(id, name, py) values('91','刘彦利','LYL'); insert into user(id, name, py) values('92','刘益存','LYC'); insert into user(id, name, py) values('93','龙子苹','LZP'); insert into user(id, name, py) values('94','卢秀剑','LXJ'); insert into user(id, name, py) values('95','罗乔华','LQH'); insert into user(id, name, py) values('96','罗希清','LXQ'); insert into user(id, name, py) values('97','马家兰','MJL'); insert into user(id, name, py) values('98','马莲莹','MLY'); insert into user(id, name, py) values('99','马宁文','MNW'); insert into user(id, name, py) values('100','马水鹏','MSP'); insert into user(id, name, py) values('101','孟三云','MSY'); insert into user(id, name, py) values('102','孟寿云','MSY'); insert into user(id, name, py) values('103','聂伟元','NWY'); insert into user(id, name, py) values('104','潘永飞','PYF'); insert into user(id, name, py) values('105','彭健颖','PJY'); insert into user(id, name, py) values('106','钱文松','QWS'); insert into user(id, name, py) values('107','屈江珍','QJZ'); insert into user(id, name, py) values('108','邵建林','SJL'); insert into user(id, name, py) values('109','施家晖','SJZ'); insert into user(id, name, py) values('110','施艺英','SYY'); insert into user(id, name, py) values('111','孙常程','SCC'); insert into user(id, name, py) values('112','谭佳盈','TJY'); insert into user(id, name, py) values('113','唐春珊','TCS'); insert into user(id, name, py) values('114','唐军霞','TJX'); insert into user(id, name, py) values('115','唐里丽','TLL'); insert into user(id, name, py) values('116','陶姐华','TJH'); insert into user(id, name, py) values('117','万圻艳','WZY'); insert into user(id, name, py) values('118','王傲凤','WAF'); insert into user(id, name, py) values('119','王德英','WDY'); insert into user(id, name, py) values('120','王鼎华','WDH'); insert into user(id, name, py) values('121','王慧','WH'); insert into user(id, name, py) values('122','王佳光','WJG'); insert into user(id, name, py) values('123','王家胜','WJS'); insert into user(id, name, py) values('124','王竞飞','WJF'); insert into user(id, name, py) values('125','王科磊','WKL'); insert into user(id, name, py) values('126','王丽章','WLZ'); insert into user(id, name, py) values('127','王励苗','WLM'); insert into user(id, name, py) values('128','王美东','WMD'); insert into user(id, name, py) values('129','王美媛','WMZ'); insert into user(id, name, py) values('130','王蕊颖','WRY'); insert into user(id, name, py) values('131','王士成','WSC'); insert into user(id, name, py) values('132','王熙斌','WXB'); insert into user(id, name, py) values('133','王香军','WXJ'); insert into user(id, name, py) values('134','王休娜','WXN'); insert into user(id, name, py) values('135','王仪行','WYX'); insert into user(id, name, py) values('136','王赢基','WYJ'); insert into user(id, name, py) values('137','王云芯','WYX'); insert into user(id, name, py) values('138','王郑林','WZL'); insert into user(id, name, py) values('139','王治良','WZL'); insert into user(id, name, py) values('140','王忠宇','WZY'); insert into user(id, name, py) values('141','王子冰','WZB'); insert into user(id, name, py) values('142','韦新裕','WXY'); insert into user(id, name, py) values('143','魏复冉','WFR'); insert into user(id, name, py) values('144','吴翰志','WHZ'); insert into user(id, name, py) values('145','吴美森','WMS'); insert into user(id, name, py) values('146','吴翔良','WXL'); insert into user(id, name, py) values('147','吴艳伟','WYW'); insert into user(id, name, py) values('148','吴钲辉','WZH'); insert into user(id, name, py) values('149','向盼洛','XPL'); insert into user(id, name, py) values('150','萧恩','XE'); insert into user(id, name, py) values('151','萧军杰','XJJ'); insert into user(id, name, py) values('152','萧圣梅','XSM'); insert into user(id, name, py) values('153','谢辰吉','XCJ'); insert into user(id, name, py) values('154','徐郎求','XLQ'); insert into user(id, name, py) values('155','徐铭森','XMS'); insert into user(id, name, py) values('156','徐蓉伟','XRW'); insert into user(id, name, py) values('157','许为梧','XWW'); insert into user(id, name, py) values('158','阎皓河','YZH'); insert into user(id, name, py) values('159','阎思华','YSH'); insert into user(id, name, py) values('160','杨爱秀','YAX'); insert into user(id, name, py) values('161','杨昆飞','YKF'); insert into user(id, name, py) values('162','杨良林','YLL'); insert into user(id, name, py) values('163','杨少君','YSJ'); insert into user(id, name, py) values('164','杨玉丽','YYL'); insert into user(id, name, py) values('165','杨之安','YZA'); insert into user(id, name, py) values('166','尤榕锋','YZF'); insert into user(id, name, py) values('167','余俊珠','YJZ'); insert into user(id, name, py) values('168','袁江蔓','YJM'); insert into user(id, name, py) values('169','张必翰','ZBH'); insert into user(id, name, py) values('170','张昌颜','ZCY'); insert into user(id, name, py) values('171','张恩星','ZEX'); insert into user(id, name, py) values('172','张飞强','ZFQ'); insert into user(id, name, py) values('173','张凤焯','ZFZ'); insert into user(id, name, py) values('174','张国强','ZGQ'); insert into user(id, name, py) values('175','张计欣','ZJX'); insert into user(id, name, py) values('176','张家颖','ZJY'); insert into user(id, name, py) values('177','张金安','ZJA'); insert into user(id, name, py) values('178','张莉','ZL'); insert into user(id, name, py) values('179','张米龙','ZML'); insert into user(id, name, py) values('180','张善渊','ZSY'); insert into user(id, name, py) values('181','张万敏','ZWM'); insert into user(id, name, py) values('182','张晓林','ZXL'); insert into user(id, name, py) values('183','张秀高','ZXG'); ================================================ FILE: src/test/resources/cirrodata/mybatis-config-pagesizezero.xml ================================================ ================================================ FILE: src/test/resources/cirrodata/mybatis-config-reasonable.xml ================================================ ================================================ FILE: src/test/resources/cirrodata/mybatis-config-rowbounds.xml ================================================ ================================================ FILE: src/test/resources/cirrodata/mybatis-config.xml ================================================ ================================================ FILE: src/test/resources/com/github/pagehelper/mapper/UserMapper.xml ================================================ and ${criterion.condition} and ${criterion.condition} #{criterion.value} and ${criterion.condition} #{criterion.value} and #{criterion.secondValue} and ${criterion.condition} #{listItem} ================================================ FILE: src/test/resources/db2/mybatis-config-pagesizezero.xml ================================================ ================================================ FILE: src/test/resources/db2/mybatis-config-reasonable.xml ================================================ ================================================ FILE: src/test/resources/db2/mybatis-config-rowbounds.xml ================================================ ================================================ FILE: src/test/resources/db2/mybatis-config.xml ================================================ ================================================ FILE: src/test/resources/derby/derby.sql ================================================ /* * The MIT License (MIT) * * Copyright (c) 2014-2022 abel533@gmail.com * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ drop table user; create table user ( id integer, name varchar(32), py varchar(5) ); insert into user(id, name, py) values ('1', '毕淑儒', 'BSR'); insert into user(id, name, py) values('2','蔡兴熙','CXX'); insert into user(id, name, py) values('3','曾三杰','ZSJ'); insert into user(id, name, py) values('4','常元琴','CYQ'); insert into user(id, name, py) values('5','陈栋芬','CDF'); insert into user(id, name, py) values('6','陈宁婷','CNZ'); insert into user(id, name, py) values('7','陈瑞','CR'); insert into user(id, name, py) values('8','陈武宵','CWX'); insert into user(id, name, py) values('9','陈晓丽','CXL'); insert into user(id, name, py) values('10','陈翼涛','CYT'); insert into user(id, name, py) values('11','陈宇然','CYR'); insert into user(id, name, py) values('12','陈震','CZ'); insert into user(id, name, py) values('13','程太君','CTJ'); insert into user(id, name, py) values('14','程玉娜','CYN'); insert into user(id, name, py) values('15','丛贺轩','CHX'); insert into user(id, name, py) values('16','戴国宇','DGY'); insert into user(id, name, py) values('17','戴杰亮','DJL'); insert into user(id, name, py) values('18','丁玉华','DYH'); insert into user(id, name, py) values('19','董秋明','DQM'); insert into user(id, name, py) values('20','董政厚','DZH'); insert into user(id, name, py) values('21','杜玉焱','DYZ'); insert into user(id, name, py) values('22','段瑜芝','DZZ'); insert into user(id, name, py) values('23','傅广友','FGY'); insert into user(id, name, py) values('24','傅井飞','FJF'); insert into user(id, name, py) values('25','高辉涛','GHT'); insert into user(id, name, py) values('26','高龙飞','GLF'); insert into user(id, name, py) values('27','高汝英','GRY'); insert into user(id, name, py) values('28','高云天','GYT'); insert into user(id, name, py) values('29','郭义民','GYM'); insert into user(id, name, py) values('30','郭永洪','GYH'); insert into user(id, name, py) values('31','韩国茜','HGZ'); insert into user(id, name, py) values('32','韩龙康','HLK'); insert into user(id, name, py) values('33','韩伟佳','HWJ'); insert into user(id, name, py) values('34','韩扬谦','HYQ'); insert into user(id, name, py) values('35','郝静生','HJS'); insert into user(id, name, py) values('36','何柏红','HBH'); insert into user(id, name, py) values('37','何彩智','HCZ'); insert into user(id, name, py) values('38','何陶增','HTZ'); insert into user(id, name, py) values('39','何薇','HZ'); insert into user(id, name, py) values('40','何小凡','HXF'); insert into user(id, name, py) values('41','何振平','HZP'); insert into user(id, name, py) values('42','洪彩辉','HCH'); insert into user(id, name, py) values('43','胡仕明','HSM'); insert into user(id, name, py) values('44','黄建朋','HJP'); insert into user(id, name, py) values('45','黄祥荣','HXR'); insert into user(id, name, py) values('46','黄璇平','HZP'); insert into user(id, name, py) values('47','贾茂飞','JMF'); insert into user(id, name, py) values('48','李迪茹','LDR'); insert into user(id, name, py) values('49','李桂博','LGB'); insert into user(id, name, py) values('50','李国祯','LGZ'); insert into user(id, name, py) values('51','李宏川','LHC'); insert into user(id, name, py) values('52','李梅','LM'); insert into user(id, name, py) values('53','李媚文','LMW'); insert into user(id, name, py) values('54','李孟惠','LMH'); insert into user(id, name, py) values('55','李南懋','LNZ'); insert into user(id, name, py) values('56','李鹏龙','LPL'); insert into user(id, name, py) values('57','李诗庸','LSY'); insert into user(id, name, py) values('58','李姝勇','LZY'); insert into user(id, name, py) values('59','李树鹏','LSP'); insert into user(id, name, py) values('60','李薇红','LZH'); insert into user(id, name, py) values('61','李文章','LWZ'); insert into user(id, name, py) values('62','李星佳','LXJ'); insert into user(id, name, py) values('63','李兴','LX'); insert into user(id, name, py) values('64','李秀倩','LXZ'); insert into user(id, name, py) values('65','李艳生','LYS'); insert into user(id, name, py) values('66','李燕金','LYJ'); insert into user(id, name, py) values('67','李玉彪','LYB'); insert into user(id, name, py) values('68','李振峰','LZF'); insert into user(id, name, py) values('69','梁斌芳','LBF'); insert into user(id, name, py) values('70','梁国云','LGY'); insert into user(id, name, py) values('71','梁巧爱','LQA'); insert into user(id, name, py) values('72','梁照金','LZJ'); insert into user(id, name, py) values('73','林婧美','LZM'); insert into user(id, name, py) values('74','林沛寿','LPS'); insert into user(id, name, py) values('75','林薇程','LZC'); insert into user(id, name, py) values('76','林伟玉','LWY'); insert into user(id, name, py) values('77','林艺玲','LYL'); insert into user(id, name, py) values('78','刘睿','LR'); insert into user(id, name, py) values('79','刘芊芊','LQQ'); insert into user(id, name, py) values('80','刘海波','LHB'); insert into user(id, name, py) values('81','刘斓琴','LZQ'); insert into user(id, name, py) values('82','刘磊东','LLD'); insert into user(id, name, py) values('83','刘明琪','LMZ'); insert into user(id, name, py) values('84','刘铭恩','LME'); insert into user(id, name, py) values('85','刘任恺','LRZ'); insert into user(id, name, py) values('86','刘水秋','LSQ'); insert into user(id, name, py) values('87','刘文萱','LWZ'); insert into user(id, name, py) values('88','刘祥瑶','LXY'); insert into user(id, name, py) values('89','刘薪坪','LXP'); insert into user(id, name, py) values('90','刘秀涛','LXT'); insert into user(id, name, py) values('91','刘彦利','LYL'); insert into user(id, name, py) values('92','刘益存','LYC'); insert into user(id, name, py) values('93','龙子苹','LZP'); insert into user(id, name, py) values('94','卢秀剑','LXJ'); insert into user(id, name, py) values('95','罗乔华','LQH'); insert into user(id, name, py) values('96','罗希清','LXQ'); insert into user(id, name, py) values('97','马家兰','MJL'); insert into user(id, name, py) values('98','马莲莹','MLY'); insert into user(id, name, py) values('99','马宁文','MNW'); insert into user(id, name, py) values('100','马水鹏','MSP'); insert into user(id, name, py) values('101','孟三云','MSY'); insert into user(id, name, py) values('102','孟寿云','MSY'); insert into user(id, name, py) values('103','聂伟元','NWY'); insert into user(id, name, py) values('104','潘永飞','PYF'); insert into user(id, name, py) values('105','彭健颖','PJY'); insert into user(id, name, py) values('106','钱文松','QWS'); insert into user(id, name, py) values('107','屈江珍','QJZ'); insert into user(id, name, py) values('108','邵建林','SJL'); insert into user(id, name, py) values('109','施家晖','SJZ'); insert into user(id, name, py) values('110','施艺英','SYY'); insert into user(id, name, py) values('111','孙常程','SCC'); insert into user(id, name, py) values('112','谭佳盈','TJY'); insert into user(id, name, py) values('113','唐春珊','TCS'); insert into user(id, name, py) values('114','唐军霞','TJX'); insert into user(id, name, py) values('115','唐里丽','TLL'); insert into user(id, name, py) values('116','陶姐华','TJH'); insert into user(id, name, py) values('117','万圻艳','WZY'); insert into user(id, name, py) values('118','王傲凤','WAF'); insert into user(id, name, py) values('119','王德英','WDY'); insert into user(id, name, py) values('120','王鼎华','WDH'); insert into user(id, name, py) values('121','王慧','WH'); insert into user(id, name, py) values('122','王佳光','WJG'); insert into user(id, name, py) values('123','王家胜','WJS'); insert into user(id, name, py) values('124','王竞飞','WJF'); insert into user(id, name, py) values('125','王科磊','WKL'); insert into user(id, name, py) values('126','王丽章','WLZ'); insert into user(id, name, py) values('127','王励苗','WLM'); insert into user(id, name, py) values('128','王美东','WMD'); insert into user(id, name, py) values('129','王美媛','WMZ'); insert into user(id, name, py) values('130','王蕊颖','WRY'); insert into user(id, name, py) values('131','王士成','WSC'); insert into user(id, name, py) values('132','王熙斌','WXB'); insert into user(id, name, py) values('133','王香军','WXJ'); insert into user(id, name, py) values('134','王休娜','WXN'); insert into user(id, name, py) values('135','王仪行','WYX'); insert into user(id, name, py) values('136','王赢基','WYJ'); insert into user(id, name, py) values('137','王云芯','WYX'); insert into user(id, name, py) values('138','王郑林','WZL'); insert into user(id, name, py) values('139','王治良','WZL'); insert into user(id, name, py) values('140','王忠宇','WZY'); insert into user(id, name, py) values('141','王子冰','WZB'); insert into user(id, name, py) values('142','韦新裕','WXY'); insert into user(id, name, py) values('143','魏复冉','WFR'); insert into user(id, name, py) values('144','吴翰志','WHZ'); insert into user(id, name, py) values('145','吴美森','WMS'); insert into user(id, name, py) values('146','吴翔良','WXL'); insert into user(id, name, py) values('147','吴艳伟','WYW'); insert into user(id, name, py) values('148','吴钲辉','WZH'); insert into user(id, name, py) values('149','向盼洛','XPL'); insert into user(id, name, py) values('150','萧恩','XE'); insert into user(id, name, py) values('151','萧军杰','XJJ'); insert into user(id, name, py) values('152','萧圣梅','XSM'); insert into user(id, name, py) values('153','谢辰吉','XCJ'); insert into user(id, name, py) values('154','徐郎求','XLQ'); insert into user(id, name, py) values('155','徐铭森','XMS'); insert into user(id, name, py) values('156','徐蓉伟','XRW'); insert into user(id, name, py) values('157','许为梧','XWW'); insert into user(id, name, py) values('158','阎皓河','YZH'); insert into user(id, name, py) values('159','阎思华','YSH'); insert into user(id, name, py) values('160','杨爱秀','YAX'); insert into user(id, name, py) values('161','杨昆飞','YKF'); insert into user(id, name, py) values('162','杨良林','YLL'); insert into user(id, name, py) values('163','杨少君','YSJ'); insert into user(id, name, py) values('164','杨玉丽','YYL'); insert into user(id, name, py) values('165','杨之安','YZA'); insert into user(id, name, py) values('166','尤榕锋','YZF'); insert into user(id, name, py) values('167','余俊珠','YJZ'); insert into user(id, name, py) values('168','袁江蔓','YJM'); insert into user(id, name, py) values('169','张必翰','ZBH'); insert into user(id, name, py) values('170','张昌颜','ZCY'); insert into user(id, name, py) values('171','张恩星','ZEX'); insert into user(id, name, py) values('172','张飞强','ZFQ'); insert into user(id, name, py) values('173','张凤焯','ZFZ'); insert into user(id, name, py) values('174','张国强','ZGQ'); insert into user(id, name, py) values('175','张计欣','ZJX'); insert into user(id, name, py) values('176','张家颖','ZJY'); insert into user(id, name, py) values('177','张金安','ZJA'); insert into user(id, name, py) values('178','张莉','ZL'); insert into user(id, name, py) values('179','张米龙','ZML'); insert into user(id, name, py) values('180','张善渊','ZSY'); insert into user(id, name, py) values('181','张万敏','ZWM'); insert into user(id, name, py) values('182','张晓林','ZXL'); insert into user(id, name, py) values('183','张秀高','ZXG'); ================================================ FILE: src/test/resources/derby/mybatis-config-pagesizezero.xml ================================================ ================================================ FILE: src/test/resources/derby/mybatis-config-reasonable.xml ================================================ ================================================ FILE: src/test/resources/derby/mybatis-config-rowbounds.xml ================================================ ================================================ FILE: src/test/resources/derby/mybatis-config.xml ================================================ ================================================ FILE: src/test/resources/h2/h2.sql ================================================ /* * The MIT License (MIT) * * Copyright (c) 2014-2022 abel533@gmail.com * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ drop table user if exists; create table user ( id integer, name varchar(32), py varchar(5) ); insert into user(id, name, py) values ('1', '毕淑儒', 'BSR'); insert into user(id, name, py) values('2','蔡兴熙','CXX'); insert into user(id, name, py) values('3','曾三杰','ZSJ'); insert into user(id, name, py) values('4','常元琴','CYQ'); insert into user(id, name, py) values('5','陈栋芬','CDF'); insert into user(id, name, py) values('6','陈宁婷','CNZ'); insert into user(id, name, py) values('7','陈瑞','CR'); insert into user(id, name, py) values('8','陈武宵','CWX'); insert into user(id, name, py) values('9','陈晓丽','CXL'); insert into user(id, name, py) values('10','陈翼涛','CYT'); insert into user(id, name, py) values('11','陈宇然','CYR'); insert into user(id, name, py) values('12','陈震','CZ'); insert into user(id, name, py) values('13','程太君','CTJ'); insert into user(id, name, py) values('14','程玉娜','CYN'); insert into user(id, name, py) values('15','丛贺轩','CHX'); insert into user(id, name, py) values('16','戴国宇','DGY'); insert into user(id, name, py) values('17','戴杰亮','DJL'); insert into user(id, name, py) values('18','丁玉华','DYH'); insert into user(id, name, py) values('19','董秋明','DQM'); insert into user(id, name, py) values('20','董政厚','DZH'); insert into user(id, name, py) values('21','杜玉焱','DYZ'); insert into user(id, name, py) values('22','段瑜芝','DZZ'); insert into user(id, name, py) values('23','傅广友','FGY'); insert into user(id, name, py) values('24','傅井飞','FJF'); insert into user(id, name, py) values('25','高辉涛','GHT'); insert into user(id, name, py) values('26','高龙飞','GLF'); insert into user(id, name, py) values('27','高汝英','GRY'); insert into user(id, name, py) values('28','高云天','GYT'); insert into user(id, name, py) values('29','郭义民','GYM'); insert into user(id, name, py) values('30','郭永洪','GYH'); insert into user(id, name, py) values('31','韩国茜','HGZ'); insert into user(id, name, py) values('32','韩龙康','HLK'); insert into user(id, name, py) values('33','韩伟佳','HWJ'); insert into user(id, name, py) values('34','韩扬谦','HYQ'); insert into user(id, name, py) values('35','郝静生','HJS'); insert into user(id, name, py) values('36','何柏红','HBH'); insert into user(id, name, py) values('37','何彩智','HCZ'); insert into user(id, name, py) values('38','何陶增','HTZ'); insert into user(id, name, py) values('39','何薇','HZ'); insert into user(id, name, py) values('40','何小凡','HXF'); insert into user(id, name, py) values('41','何振平','HZP'); insert into user(id, name, py) values('42','洪彩辉','HCH'); insert into user(id, name, py) values('43','胡仕明','HSM'); insert into user(id, name, py) values('44','黄建朋','HJP'); insert into user(id, name, py) values('45','黄祥荣','HXR'); insert into user(id, name, py) values('46','黄璇平','HZP'); insert into user(id, name, py) values('47','贾茂飞','JMF'); insert into user(id, name, py) values('48','李迪茹','LDR'); insert into user(id, name, py) values('49','李桂博','LGB'); insert into user(id, name, py) values('50','李国祯','LGZ'); insert into user(id, name, py) values('51','李宏川','LHC'); insert into user(id, name, py) values('52','李梅','LM'); insert into user(id, name, py) values('53','李媚文','LMW'); insert into user(id, name, py) values('54','李孟惠','LMH'); insert into user(id, name, py) values('55','李南懋','LNZ'); insert into user(id, name, py) values('56','李鹏龙','LPL'); insert into user(id, name, py) values('57','李诗庸','LSY'); insert into user(id, name, py) values('58','李姝勇','LZY'); insert into user(id, name, py) values('59','李树鹏','LSP'); insert into user(id, name, py) values('60','李薇红','LZH'); insert into user(id, name, py) values('61','李文章','LWZ'); insert into user(id, name, py) values('62','李星佳','LXJ'); insert into user(id, name, py) values('63','李兴','LX'); insert into user(id, name, py) values('64','李秀倩','LXZ'); insert into user(id, name, py) values('65','李艳生','LYS'); insert into user(id, name, py) values('66','李燕金','LYJ'); insert into user(id, name, py) values('67','李玉彪','LYB'); insert into user(id, name, py) values('68','李振峰','LZF'); insert into user(id, name, py) values('69','梁斌芳','LBF'); insert into user(id, name, py) values('70','梁国云','LGY'); insert into user(id, name, py) values('71','梁巧爱','LQA'); insert into user(id, name, py) values('72','梁照金','LZJ'); insert into user(id, name, py) values('73','林婧美','LZM'); insert into user(id, name, py) values('74','林沛寿','LPS'); insert into user(id, name, py) values('75','林薇程','LZC'); insert into user(id, name, py) values('76','林伟玉','LWY'); insert into user(id, name, py) values('77','林艺玲','LYL'); insert into user(id, name, py) values('78','刘睿','LR'); insert into user(id, name, py) values('79','刘芊芊','LQQ'); insert into user(id, name, py) values('80','刘海波','LHB'); insert into user(id, name, py) values('81','刘斓琴','LZQ'); insert into user(id, name, py) values('82','刘磊东','LLD'); insert into user(id, name, py) values('83','刘明琪','LMZ'); insert into user(id, name, py) values('84','刘铭恩','LME'); insert into user(id, name, py) values('85','刘任恺','LRZ'); insert into user(id, name, py) values('86','刘水秋','LSQ'); insert into user(id, name, py) values('87','刘文萱','LWZ'); insert into user(id, name, py) values('88','刘祥瑶','LXY'); insert into user(id, name, py) values('89','刘薪坪','LXP'); insert into user(id, name, py) values('90','刘秀涛','LXT'); insert into user(id, name, py) values('91','刘彦利','LYL'); insert into user(id, name, py) values('92','刘益存','LYC'); insert into user(id, name, py) values('93','龙子苹','LZP'); insert into user(id, name, py) values('94','卢秀剑','LXJ'); insert into user(id, name, py) values('95','罗乔华','LQH'); insert into user(id, name, py) values('96','罗希清','LXQ'); insert into user(id, name, py) values('97','马家兰','MJL'); insert into user(id, name, py) values('98','马莲莹','MLY'); insert into user(id, name, py) values('99','马宁文','MNW'); insert into user(id, name, py) values('100','马水鹏','MSP'); insert into user(id, name, py) values('101','孟三云','MSY'); insert into user(id, name, py) values('102','孟寿云','MSY'); insert into user(id, name, py) values('103','聂伟元','NWY'); insert into user(id, name, py) values('104','潘永飞','PYF'); insert into user(id, name, py) values('105','彭健颖','PJY'); insert into user(id, name, py) values('106','钱文松','QWS'); insert into user(id, name, py) values('107','屈江珍','QJZ'); insert into user(id, name, py) values('108','邵建林','SJL'); insert into user(id, name, py) values('109','施家晖','SJZ'); insert into user(id, name, py) values('110','施艺英','SYY'); insert into user(id, name, py) values('111','孙常程','SCC'); insert into user(id, name, py) values('112','谭佳盈','TJY'); insert into user(id, name, py) values('113','唐春珊','TCS'); insert into user(id, name, py) values('114','唐军霞','TJX'); insert into user(id, name, py) values('115','唐里丽','TLL'); insert into user(id, name, py) values('116','陶姐华','TJH'); insert into user(id, name, py) values('117','万圻艳','WZY'); insert into user(id, name, py) values('118','王傲凤','WAF'); insert into user(id, name, py) values('119','王德英','WDY'); insert into user(id, name, py) values('120','王鼎华','WDH'); insert into user(id, name, py) values('121','王慧','WH'); insert into user(id, name, py) values('122','王佳光','WJG'); insert into user(id, name, py) values('123','王家胜','WJS'); insert into user(id, name, py) values('124','王竞飞','WJF'); insert into user(id, name, py) values('125','王科磊','WKL'); insert into user(id, name, py) values('126','王丽章','WLZ'); insert into user(id, name, py) values('127','王励苗','WLM'); insert into user(id, name, py) values('128','王美东','WMD'); insert into user(id, name, py) values('129','王美媛','WMZ'); insert into user(id, name, py) values('130','王蕊颖','WRY'); insert into user(id, name, py) values('131','王士成','WSC'); insert into user(id, name, py) values('132','王熙斌','WXB'); insert into user(id, name, py) values('133','王香军','WXJ'); insert into user(id, name, py) values('134','王休娜','WXN'); insert into user(id, name, py) values('135','王仪行','WYX'); insert into user(id, name, py) values('136','王赢基','WYJ'); insert into user(id, name, py) values('137','王云芯','WYX'); insert into user(id, name, py) values('138','王郑林','WZL'); insert into user(id, name, py) values('139','王治良','WZL'); insert into user(id, name, py) values('140','王忠宇','WZY'); insert into user(id, name, py) values('141','王子冰','WZB'); insert into user(id, name, py) values('142','韦新裕','WXY'); insert into user(id, name, py) values('143','魏复冉','WFR'); insert into user(id, name, py) values('144','吴翰志','WHZ'); insert into user(id, name, py) values('145','吴美森','WMS'); insert into user(id, name, py) values('146','吴翔良','WXL'); insert into user(id, name, py) values('147','吴艳伟','WYW'); insert into user(id, name, py) values('148','吴钲辉','WZH'); insert into user(id, name, py) values('149','向盼洛','XPL'); insert into user(id, name, py) values('150','萧恩','XE'); insert into user(id, name, py) values('151','萧军杰','XJJ'); insert into user(id, name, py) values('152','萧圣梅','XSM'); insert into user(id, name, py) values('153','谢辰吉','XCJ'); insert into user(id, name, py) values('154','徐郎求','XLQ'); insert into user(id, name, py) values('155','徐铭森','XMS'); insert into user(id, name, py) values('156','徐蓉伟','XRW'); insert into user(id, name, py) values('157','许为梧','XWW'); insert into user(id, name, py) values('158','阎皓河','YZH'); insert into user(id, name, py) values('159','阎思华','YSH'); insert into user(id, name, py) values('160','杨爱秀','YAX'); insert into user(id, name, py) values('161','杨昆飞','YKF'); insert into user(id, name, py) values('162','杨良林','YLL'); insert into user(id, name, py) values('163','杨少君','YSJ'); insert into user(id, name, py) values('164','杨玉丽','YYL'); insert into user(id, name, py) values('165','杨之安','YZA'); insert into user(id, name, py) values('166','尤榕锋','YZF'); insert into user(id, name, py) values('167','余俊珠','YJZ'); insert into user(id, name, py) values('168','袁江蔓','YJM'); insert into user(id, name, py) values('169','张必翰','ZBH'); insert into user(id, name, py) values('170','张昌颜','ZCY'); insert into user(id, name, py) values('171','张恩星','ZEX'); insert into user(id, name, py) values('172','张飞强','ZFQ'); insert into user(id, name, py) values('173','张凤焯','ZFZ'); insert into user(id, name, py) values('174','张国强','ZGQ'); insert into user(id, name, py) values('175','张计欣','ZJX'); insert into user(id, name, py) values('176','张家颖','ZJY'); insert into user(id, name, py) values('177','张金安','ZJA'); insert into user(id, name, py) values('178','张莉','ZL'); insert into user(id, name, py) values('179','张米龙','ZML'); insert into user(id, name, py) values('180','张善渊','ZSY'); insert into user(id, name, py) values('181','张万敏','ZWM'); insert into user(id, name, py) values('182','张晓林','ZXL'); insert into user(id, name, py) values('183','张秀高','ZXG'); ================================================ FILE: src/test/resources/h2/mybatis-config-pagesizezero.xml ================================================ ================================================ FILE: src/test/resources/h2/mybatis-config-reasonable.xml ================================================ ================================================ FILE: src/test/resources/h2/mybatis-config-rowbounds.xml ================================================ ================================================ FILE: src/test/resources/h2/mybatis-config.xml ================================================ ================================================ FILE: src/test/resources/hsqldb/hsqldb.sql ================================================ /* * The MIT License (MIT) * * Copyright (c) 2014-2022 abel533@gmail.com * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ drop table user if exists; create table user ( id integer, name varchar(32), py varchar(5) ); insert into user(id, name, py) values ('1', '毕淑儒', 'BSR'); insert into user(id, name, py) values('2','蔡兴熙','CXX'); insert into user(id, name, py) values('3','曾三杰','ZSJ'); insert into user(id, name, py) values('4','常元琴','CYQ'); insert into user(id, name, py) values('5','陈栋芬','CDF'); insert into user(id, name, py) values('6','陈宁婷','CNZ'); insert into user(id, name, py) values('7','陈瑞','CR'); insert into user(id, name, py) values('8','陈武宵','CWX'); insert into user(id, name, py) values('9','陈晓丽','CXL'); insert into user(id, name, py) values('10','陈翼涛','CYT'); insert into user(id, name, py) values('11','陈宇然','CYR'); insert into user(id, name, py) values('12','陈震','CZ'); insert into user(id, name, py) values('13','程太君','CTJ'); insert into user(id, name, py) values('14','程玉娜','CYN'); insert into user(id, name, py) values('15','丛贺轩','CHX'); insert into user(id, name, py) values('16','戴国宇','DGY'); insert into user(id, name, py) values('17','戴杰亮','DJL'); insert into user(id, name, py) values('18','丁玉华','DYH'); insert into user(id, name, py) values('19','董秋明','DQM'); insert into user(id, name, py) values('20','董政厚','DZH'); insert into user(id, name, py) values('21','杜玉焱','DYZ'); insert into user(id, name, py) values('22','段瑜芝','DZZ'); insert into user(id, name, py) values('23','傅广友','FGY'); insert into user(id, name, py) values('24','傅井飞','FJF'); insert into user(id, name, py) values('25','高辉涛','GHT'); insert into user(id, name, py) values('26','高龙飞','GLF'); insert into user(id, name, py) values('27','高汝英','GRY'); insert into user(id, name, py) values('28','高云天','GYT'); insert into user(id, name, py) values('29','郭义民','GYM'); insert into user(id, name, py) values('30','郭永洪','GYH'); insert into user(id, name, py) values('31','韩国茜','HGZ'); insert into user(id, name, py) values('32','韩龙康','HLK'); insert into user(id, name, py) values('33','韩伟佳','HWJ'); insert into user(id, name, py) values('34','韩扬谦','HYQ'); insert into user(id, name, py) values('35','郝静生','HJS'); insert into user(id, name, py) values('36','何柏红','HBH'); insert into user(id, name, py) values('37','何彩智','HCZ'); insert into user(id, name, py) values('38','何陶增','HTZ'); insert into user(id, name, py) values('39','何薇','HZ'); insert into user(id, name, py) values('40','何小凡','HXF'); insert into user(id, name, py) values('41','何振平','HZP'); insert into user(id, name, py) values('42','洪彩辉','HCH'); insert into user(id, name, py) values('43','胡仕明','HSM'); insert into user(id, name, py) values('44','黄建朋','HJP'); insert into user(id, name, py) values('45','黄祥荣','HXR'); insert into user(id, name, py) values('46','黄璇平','HZP'); insert into user(id, name, py) values('47','贾茂飞','JMF'); insert into user(id, name, py) values('48','李迪茹','LDR'); insert into user(id, name, py) values('49','李桂博','LGB'); insert into user(id, name, py) values('50','李国祯','LGZ'); insert into user(id, name, py) values('51','李宏川','LHC'); insert into user(id, name, py) values('52','李梅','LM'); insert into user(id, name, py) values('53','李媚文','LMW'); insert into user(id, name, py) values('54','李孟惠','LMH'); insert into user(id, name, py) values('55','李南懋','LNZ'); insert into user(id, name, py) values('56','李鹏龙','LPL'); insert into user(id, name, py) values('57','李诗庸','LSY'); insert into user(id, name, py) values('58','李姝勇','LZY'); insert into user(id, name, py) values('59','李树鹏','LSP'); insert into user(id, name, py) values('60','李薇红','LZH'); insert into user(id, name, py) values('61','李文章','LWZ'); insert into user(id, name, py) values('62','李星佳','LXJ'); insert into user(id, name, py) values('63','李兴','LX'); insert into user(id, name, py) values('64','李秀倩','LXZ'); insert into user(id, name, py) values('65','李艳生','LYS'); insert into user(id, name, py) values('66','李燕金','LYJ'); insert into user(id, name, py) values('67','李玉彪','LYB'); insert into user(id, name, py) values('68','李振峰','LZF'); insert into user(id, name, py) values('69','梁斌芳','LBF'); insert into user(id, name, py) values('70','梁国云','LGY'); insert into user(id, name, py) values('71','梁巧爱','LQA'); insert into user(id, name, py) values('72','梁照金','LZJ'); insert into user(id, name, py) values('73','林婧美','LZM'); insert into user(id, name, py) values('74','林沛寿','LPS'); insert into user(id, name, py) values('75','林薇程','LZC'); insert into user(id, name, py) values('76','林伟玉','LWY'); insert into user(id, name, py) values('77','林艺玲','LYL'); insert into user(id, name, py) values('78','刘睿','LR'); insert into user(id, name, py) values('79','刘芊芊','LQQ'); insert into user(id, name, py) values('80','刘海波','LHB'); insert into user(id, name, py) values('81','刘斓琴','LZQ'); insert into user(id, name, py) values('82','刘磊东','LLD'); insert into user(id, name, py) values('83','刘明琪','LMZ'); insert into user(id, name, py) values('84','刘铭恩','LME'); insert into user(id, name, py) values('85','刘任恺','LRZ'); insert into user(id, name, py) values('86','刘水秋','LSQ'); insert into user(id, name, py) values('87','刘文萱','LWZ'); insert into user(id, name, py) values('88','刘祥瑶','LXY'); insert into user(id, name, py) values('89','刘薪坪','LXP'); insert into user(id, name, py) values('90','刘秀涛','LXT'); insert into user(id, name, py) values('91','刘彦利','LYL'); insert into user(id, name, py) values('92','刘益存','LYC'); insert into user(id, name, py) values('93','龙子苹','LZP'); insert into user(id, name, py) values('94','卢秀剑','LXJ'); insert into user(id, name, py) values('95','罗乔华','LQH'); insert into user(id, name, py) values('96','罗希清','LXQ'); insert into user(id, name, py) values('97','马家兰','MJL'); insert into user(id, name, py) values('98','马莲莹','MLY'); insert into user(id, name, py) values('99','马宁文','MNW'); insert into user(id, name, py) values('100','马水鹏','MSP'); insert into user(id, name, py) values('101','孟三云','MSY'); insert into user(id, name, py) values('102','孟寿云','MSY'); insert into user(id, name, py) values('103','聂伟元','NWY'); insert into user(id, name, py) values('104','潘永飞','PYF'); insert into user(id, name, py) values('105','彭健颖','PJY'); insert into user(id, name, py) values('106','钱文松','QWS'); insert into user(id, name, py) values('107','屈江珍','QJZ'); insert into user(id, name, py) values('108','邵建林','SJL'); insert into user(id, name, py) values('109','施家晖','SJZ'); insert into user(id, name, py) values('110','施艺英','SYY'); insert into user(id, name, py) values('111','孙常程','SCC'); insert into user(id, name, py) values('112','谭佳盈','TJY'); insert into user(id, name, py) values('113','唐春珊','TCS'); insert into user(id, name, py) values('114','唐军霞','TJX'); insert into user(id, name, py) values('115','唐里丽','TLL'); insert into user(id, name, py) values('116','陶姐华','TJH'); insert into user(id, name, py) values('117','万圻艳','WZY'); insert into user(id, name, py) values('118','王傲凤','WAF'); insert into user(id, name, py) values('119','王德英','WDY'); insert into user(id, name, py) values('120','王鼎华','WDH'); insert into user(id, name, py) values('121','王慧','WH'); insert into user(id, name, py) values('122','王佳光','WJG'); insert into user(id, name, py) values('123','王家胜','WJS'); insert into user(id, name, py) values('124','王竞飞','WJF'); insert into user(id, name, py) values('125','王科磊','WKL'); insert into user(id, name, py) values('126','王丽章','WLZ'); insert into user(id, name, py) values('127','王励苗','WLM'); insert into user(id, name, py) values('128','王美东','WMD'); insert into user(id, name, py) values('129','王美媛','WMZ'); insert into user(id, name, py) values('130','王蕊颖','WRY'); insert into user(id, name, py) values('131','王士成','WSC'); insert into user(id, name, py) values('132','王熙斌','WXB'); insert into user(id, name, py) values('133','王香军','WXJ'); insert into user(id, name, py) values('134','王休娜','WXN'); insert into user(id, name, py) values('135','王仪行','WYX'); insert into user(id, name, py) values('136','王赢基','WYJ'); insert into user(id, name, py) values('137','王云芯','WYX'); insert into user(id, name, py) values('138','王郑林','WZL'); insert into user(id, name, py) values('139','王治良','WZL'); insert into user(id, name, py) values('140','王忠宇','WZY'); insert into user(id, name, py) values('141','王子冰','WZB'); insert into user(id, name, py) values('142','韦新裕','WXY'); insert into user(id, name, py) values('143','魏复冉','WFR'); insert into user(id, name, py) values('144','吴翰志','WHZ'); insert into user(id, name, py) values('145','吴美森','WMS'); insert into user(id, name, py) values('146','吴翔良','WXL'); insert into user(id, name, py) values('147','吴艳伟','WYW'); insert into user(id, name, py) values('148','吴钲辉','WZH'); insert into user(id, name, py) values('149','向盼洛','XPL'); insert into user(id, name, py) values('150','萧恩','XE'); insert into user(id, name, py) values('151','萧军杰','XJJ'); insert into user(id, name, py) values('152','萧圣梅','XSM'); insert into user(id, name, py) values('153','谢辰吉','XCJ'); insert into user(id, name, py) values('154','徐郎求','XLQ'); insert into user(id, name, py) values('155','徐铭森','XMS'); insert into user(id, name, py) values('156','徐蓉伟','XRW'); insert into user(id, name, py) values('157','许为梧','XWW'); insert into user(id, name, py) values('158','阎皓河','YZH'); insert into user(id, name, py) values('159','阎思华','YSH'); insert into user(id, name, py) values('160','杨爱秀','YAX'); insert into user(id, name, py) values('161','杨昆飞','YKF'); insert into user(id, name, py) values('162','杨良林','YLL'); insert into user(id, name, py) values('163','杨少君','YSJ'); insert into user(id, name, py) values('164','杨玉丽','YYL'); insert into user(id, name, py) values('165','杨之安','YZA'); insert into user(id, name, py) values('166','尤榕锋','YZF'); insert into user(id, name, py) values('167','余俊珠','YJZ'); insert into user(id, name, py) values('168','袁江蔓','YJM'); insert into user(id, name, py) values('169','张必翰','ZBH'); insert into user(id, name, py) values('170','张昌颜','ZCY'); insert into user(id, name, py) values('171','张恩星','ZEX'); insert into user(id, name, py) values('172','张飞强','ZFQ'); insert into user(id, name, py) values('173','张凤焯','ZFZ'); insert into user(id, name, py) values('174','张国强','ZGQ'); insert into user(id, name, py) values('175','张计欣','ZJX'); insert into user(id, name, py) values('176','张家颖','ZJY'); insert into user(id, name, py) values('177','张金安','ZJA'); insert into user(id, name, py) values('178','张莉','ZL'); insert into user(id, name, py) values('179','张米龙','ZML'); insert into user(id, name, py) values('180','张善渊','ZSY'); insert into user(id, name, py) values('181','张万敏','ZWM'); insert into user(id, name, py) values('182','张晓林','ZXL'); insert into user(id, name, py) values('183','张秀高','ZXG'); ================================================ FILE: src/test/resources/hsqldb/mybatis-config-autodialect.xml ================================================ ================================================ FILE: src/test/resources/hsqldb/mybatis-config-interceptor.xml ================================================ ================================================ FILE: src/test/resources/hsqldb/mybatis-config-pagesizezero.xml ================================================ ================================================ FILE: src/test/resources/hsqldb/mybatis-config-reasonable.xml ================================================ ================================================ FILE: src/test/resources/hsqldb/mybatis-config-rowbounds.xml ================================================ ================================================ FILE: src/test/resources/hsqldb/mybatis-config.xml ================================================ ================================================ FILE: src/test/resources/logback.xml ================================================ %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n ================================================ FILE: src/test/resources/mariadb/mariadb.sql ================================================ /* * The MIT License (MIT) * * Copyright (c) 2014-2022 abel533@gmail.com * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ CREATE DATABASE `pagehelper` DEFAULT CHARACTER SET utf8; CREATE USER pagehelper IDENTIFIED BY 'pagehelper'; GRANT ALL PRIVILEGES ON `pagehelper`.* TO 'pagehelper'@'%' WITH GRANT OPTION; GRANT USAGE ON *.* TO 'pagehelper'@'%' IDENTIFIED BY 'pagehelper'; DROP TABLE IF EXISTS `user`; CREATE TABLE `user` ( `id` int(11) NOT NULL AUTO_INCREMENT, `name` varchar(50) DEFAULT NULL, `py` varchar(50) DEFAULT NULL, PRIMARY KEY (`Id`) ) ENGINE=InnoDB AUTO_INCREMENT=9 DEFAULT CHARSET=utf8; insert into user(id, name, py) values('1','毕淑儒','BSR'); insert into user(id, name, py) values('2','蔡兴熙','CXX'); insert into user(id, name, py) values('3','曾三杰','ZSJ'); insert into user(id, name, py) values('4','常元琴','CYQ'); insert into user(id, name, py) values('5','陈栋芬','CDF'); insert into user(id, name, py) values('6','陈宁婷','CNZ'); insert into user(id, name, py) values('7','陈瑞','CR'); insert into user(id, name, py) values('8','陈武宵','CWX'); insert into user(id, name, py) values('9','陈晓丽','CXL'); insert into user(id, name, py) values('10','陈翼涛','CYT'); insert into user(id, name, py) values('11','陈宇然','CYR'); insert into user(id, name, py) values('12','陈震','CZ'); insert into user(id, name, py) values('13','程太君','CTJ'); insert into user(id, name, py) values('14','程玉娜','CYN'); insert into user(id, name, py) values('15','丛贺轩','CHX'); insert into user(id, name, py) values('16','戴国宇','DGY'); insert into user(id, name, py) values('17','戴杰亮','DJL'); insert into user(id, name, py) values('18','丁玉华','DYH'); insert into user(id, name, py) values('19','董秋明','DQM'); insert into user(id, name, py) values('20','董政厚','DZH'); insert into user(id, name, py) values('21','杜玉焱','DYZ'); insert into user(id, name, py) values('22','段瑜芝','DZZ'); insert into user(id, name, py) values('23','傅广友','FGY'); insert into user(id, name, py) values('24','傅井飞','FJF'); insert into user(id, name, py) values('25','高辉涛','GHT'); insert into user(id, name, py) values('26','高龙飞','GLF'); insert into user(id, name, py) values('27','高汝英','GRY'); insert into user(id, name, py) values('28','高云天','GYT'); insert into user(id, name, py) values('29','郭义民','GYM'); insert into user(id, name, py) values('30','郭永洪','GYH'); insert into user(id, name, py) values('31','韩国茜','HGZ'); insert into user(id, name, py) values('32','韩龙康','HLK'); insert into user(id, name, py) values('33','韩伟佳','HWJ'); insert into user(id, name, py) values('34','韩扬谦','HYQ'); insert into user(id, name, py) values('35','郝静生','HJS'); insert into user(id, name, py) values('36','何柏红','HBH'); insert into user(id, name, py) values('37','何彩智','HCZ'); insert into user(id, name, py) values('38','何陶增','HTZ'); insert into user(id, name, py) values('39','何薇','HZ'); insert into user(id, name, py) values('40','何小凡','HXF'); insert into user(id, name, py) values('41','何振平','HZP'); insert into user(id, name, py) values('42','洪彩辉','HCH'); insert into user(id, name, py) values('43','胡仕明','HSM'); insert into user(id, name, py) values('44','黄建朋','HJP'); insert into user(id, name, py) values('45','黄祥荣','HXR'); insert into user(id, name, py) values('46','黄璇平','HZP'); insert into user(id, name, py) values('47','贾茂飞','JMF'); insert into user(id, name, py) values('48','李迪茹','LDR'); insert into user(id, name, py) values('49','李桂博','LGB'); insert into user(id, name, py) values('50','李国祯','LGZ'); insert into user(id, name, py) values('51','李宏川','LHC'); insert into user(id, name, py) values('52','李梅','LM'); insert into user(id, name, py) values('53','李媚文','LMW'); insert into user(id, name, py) values('54','李孟惠','LMH'); insert into user(id, name, py) values('55','李南懋','LNZ'); insert into user(id, name, py) values('56','李鹏龙','LPL'); insert into user(id, name, py) values('57','李诗庸','LSY'); insert into user(id, name, py) values('58','李姝勇','LZY'); insert into user(id, name, py) values('59','李树鹏','LSP'); insert into user(id, name, py) values('60','李薇红','LZH'); insert into user(id, name, py) values('61','李文章','LWZ'); insert into user(id, name, py) values('62','李星佳','LXJ'); insert into user(id, name, py) values('63','李兴','LX'); insert into user(id, name, py) values('64','李秀倩','LXZ'); insert into user(id, name, py) values('65','李艳生','LYS'); insert into user(id, name, py) values('66','李燕金','LYJ'); insert into user(id, name, py) values('67','李玉彪','LYB'); insert into user(id, name, py) values('68','李振峰','LZF'); insert into user(id, name, py) values('69','梁斌芳','LBF'); insert into user(id, name, py) values('70','梁国云','LGY'); insert into user(id, name, py) values('71','梁巧爱','LQA'); insert into user(id, name, py) values('72','梁照金','LZJ'); insert into user(id, name, py) values('73','林婧美','LZM'); insert into user(id, name, py) values('74','林沛寿','LPS'); insert into user(id, name, py) values('75','林薇程','LZC'); insert into user(id, name, py) values('76','林伟玉','LWY'); insert into user(id, name, py) values('77','林艺玲','LYL'); insert into user(id, name, py) values('78','刘睿','LR'); insert into user(id, name, py) values('79','刘芊芊','LQQ'); insert into user(id, name, py) values('80','刘海波','LHB'); insert into user(id, name, py) values('81','刘斓琴','LZQ'); insert into user(id, name, py) values('82','刘磊东','LLD'); insert into user(id, name, py) values('83','刘明琪','LMZ'); insert into user(id, name, py) values('84','刘铭恩','LME'); insert into user(id, name, py) values('85','刘任恺','LRZ'); insert into user(id, name, py) values('86','刘水秋','LSQ'); insert into user(id, name, py) values('87','刘文萱','LWZ'); insert into user(id, name, py) values('88','刘祥瑶','LXY'); insert into user(id, name, py) values('89','刘薪坪','LXP'); insert into user(id, name, py) values('90','刘秀涛','LXT'); insert into user(id, name, py) values('91','刘彦利','LYL'); insert into user(id, name, py) values('92','刘益存','LYC'); insert into user(id, name, py) values('93','龙子苹','LZP'); insert into user(id, name, py) values('94','卢秀剑','LXJ'); insert into user(id, name, py) values('95','罗乔华','LQH'); insert into user(id, name, py) values('96','罗希清','LXQ'); insert into user(id, name, py) values('97','马家兰','MJL'); insert into user(id, name, py) values('98','马莲莹','MLY'); insert into user(id, name, py) values('99','马宁文','MNW'); insert into user(id, name, py) values('100','马水鹏','MSP'); insert into user(id, name, py) values('101','孟三云','MSY'); insert into user(id, name, py) values('102','孟寿云','MSY'); insert into user(id, name, py) values('103','聂伟元','NWY'); insert into user(id, name, py) values('104','潘永飞','PYF'); insert into user(id, name, py) values('105','彭健颖','PJY'); insert into user(id, name, py) values('106','钱文松','QWS'); insert into user(id, name, py) values('107','屈江珍','QJZ'); insert into user(id, name, py) values('108','邵建林','SJL'); insert into user(id, name, py) values('109','施家晖','SJZ'); insert into user(id, name, py) values('110','施艺英','SYY'); insert into user(id, name, py) values('111','孙常程','SCC'); insert into user(id, name, py) values('112','谭佳盈','TJY'); insert into user(id, name, py) values('113','唐春珊','TCS'); insert into user(id, name, py) values('114','唐军霞','TJX'); insert into user(id, name, py) values('115','唐里丽','TLL'); insert into user(id, name, py) values('116','陶姐华','TJH'); insert into user(id, name, py) values('117','万圻艳','WZY'); insert into user(id, name, py) values('118','王傲凤','WAF'); insert into user(id, name, py) values('119','王德英','WDY'); insert into user(id, name, py) values('120','王鼎华','WDH'); insert into user(id, name, py) values('121','王慧','WH'); insert into user(id, name, py) values('122','王佳光','WJG'); insert into user(id, name, py) values('123','王家胜','WJS'); insert into user(id, name, py) values('124','王竞飞','WJF'); insert into user(id, name, py) values('125','王科磊','WKL'); insert into user(id, name, py) values('126','王丽章','WLZ'); insert into user(id, name, py) values('127','王励苗','WLM'); insert into user(id, name, py) values('128','王美东','WMD'); insert into user(id, name, py) values('129','王美媛','WMZ'); insert into user(id, name, py) values('130','王蕊颖','WRY'); insert into user(id, name, py) values('131','王士成','WSC'); insert into user(id, name, py) values('132','王熙斌','WXB'); insert into user(id, name, py) values('133','王香军','WXJ'); insert into user(id, name, py) values('134','王休娜','WXN'); insert into user(id, name, py) values('135','王仪行','WYX'); insert into user(id, name, py) values('136','王赢基','WYJ'); insert into user(id, name, py) values('137','王云芯','WYX'); insert into user(id, name, py) values('138','王郑林','WZL'); insert into user(id, name, py) values('139','王治良','WZL'); insert into user(id, name, py) values('140','王忠宇','WZY'); insert into user(id, name, py) values('141','王子冰','WZB'); insert into user(id, name, py) values('142','韦新裕','WXY'); insert into user(id, name, py) values('143','魏复冉','WFR'); insert into user(id, name, py) values('144','吴翰志','WHZ'); insert into user(id, name, py) values('145','吴美森','WMS'); insert into user(id, name, py) values('146','吴翔良','WXL'); insert into user(id, name, py) values('147','吴艳伟','WYW'); insert into user(id, name, py) values('148','吴钲辉','WZH'); insert into user(id, name, py) values('149','向盼洛','XPL'); insert into user(id, name, py) values('150','萧恩','XE'); insert into user(id, name, py) values('151','萧军杰','XJJ'); insert into user(id, name, py) values('152','萧圣梅','XSM'); insert into user(id, name, py) values('153','谢辰吉','XCJ'); insert into user(id, name, py) values('154','徐郎求','XLQ'); insert into user(id, name, py) values('155','徐铭森','XMS'); insert into user(id, name, py) values('156','徐蓉伟','XRW'); insert into user(id, name, py) values('157','许为梧','XWW'); insert into user(id, name, py) values('158','阎皓河','YZH'); insert into user(id, name, py) values('159','阎思华','YSH'); insert into user(id, name, py) values('160','杨爱秀','YAX'); insert into user(id, name, py) values('161','杨昆飞','YKF'); insert into user(id, name, py) values('162','杨良林','YLL'); insert into user(id, name, py) values('163','杨少君','YSJ'); insert into user(id, name, py) values('164','杨玉丽','YYL'); insert into user(id, name, py) values('165','杨之安','YZA'); insert into user(id, name, py) values('166','尤榕锋','YZF'); insert into user(id, name, py) values('167','余俊珠','YJZ'); insert into user(id, name, py) values('168','袁江蔓','YJM'); insert into user(id, name, py) values('169','张必翰','ZBH'); insert into user(id, name, py) values('170','张昌颜','ZCY'); insert into user(id, name, py) values('171','张恩星','ZEX'); insert into user(id, name, py) values('172','张飞强','ZFQ'); insert into user(id, name, py) values('173','张凤焯','ZFZ'); insert into user(id, name, py) values('174','张国强','ZGQ'); insert into user(id, name, py) values('175','张计欣','ZJX'); insert into user(id, name, py) values('176','张家颖','ZJY'); insert into user(id, name, py) values('177','张金安','ZJA'); insert into user(id, name, py) values('178','张莉','ZL'); insert into user(id, name, py) values('179','张米龙','ZML'); insert into user(id, name, py) values('180','张善渊','ZSY'); insert into user(id, name, py) values('181','张万敏','ZWM'); insert into user(id, name, py) values('182','张晓林','ZXL'); insert into user(id, name, py) values('183','张秀高','ZXG'); ================================================ FILE: src/test/resources/mariadb/mybatis-config-pagesizezero.xml ================================================ ================================================ FILE: src/test/resources/mariadb/mybatis-config-reasonable.xml ================================================ ================================================ FILE: src/test/resources/mariadb/mybatis-config-rowbounds.xml ================================================ ================================================ FILE: src/test/resources/mariadb/mybatis-config.xml ================================================ ================================================ FILE: src/test/resources/mybatis-config-async-count.xml ================================================ ================================================ FILE: src/test/resources/mysql/mybatis-config-autodialect.xml ================================================ ================================================ FILE: src/test/resources/mysql/mybatis-config-interceptor.xml ================================================ ================================================ FILE: src/test/resources/mysql/mybatis-config-pagesizezero.xml ================================================ ================================================ FILE: src/test/resources/mysql/mybatis-config-reasonable.xml ================================================ ================================================ FILE: src/test/resources/mysql/mybatis-config-rowbounds.xml ================================================ ================================================ FILE: src/test/resources/mysql/mybatis-config.xml ================================================ ================================================ FILE: src/test/resources/mysql/mysql.sql ================================================ /* * The MIT License (MIT) * * Copyright (c) 2014-2022 abel533@gmail.com * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ CREATE DATABASE `pagehelper` DEFAULT CHARACTER SET utf8; USE `pagehelper`; DROP TABLE IF EXISTS `user`; CREATE TABLE `user` ( `id` int(11) NOT NULL AUTO_INCREMENT, `name` varchar(50) DEFAULT NULL, `py` varchar(50) DEFAULT NULL, PRIMARY KEY (`Id`) ) ENGINE=InnoDB AUTO_INCREMENT=9 DEFAULT CHARSET=utf8; insert into user(id, name, py) values('1','毕淑儒','BSR'); insert into user(id, name, py) values('2','蔡兴熙','CXX'); insert into user(id, name, py) values('3','曾三杰','ZSJ'); insert into user(id, name, py) values('4','常元琴','CYQ'); insert into user(id, name, py) values('5','陈栋芬','CDF'); insert into user(id, name, py) values('6','陈宁婷','CNZ'); insert into user(id, name, py) values('7','陈瑞','CR'); insert into user(id, name, py) values('8','陈武宵','CWX'); insert into user(id, name, py) values('9','陈晓丽','CXL'); insert into user(id, name, py) values('10','陈翼涛','CYT'); insert into user(id, name, py) values('11','陈宇然','CYR'); insert into user(id, name, py) values('12','陈震','CZ'); insert into user(id, name, py) values('13','程太君','CTJ'); insert into user(id, name, py) values('14','程玉娜','CYN'); insert into user(id, name, py) values('15','丛贺轩','CHX'); insert into user(id, name, py) values('16','戴国宇','DGY'); insert into user(id, name, py) values('17','戴杰亮','DJL'); insert into user(id, name, py) values('18','丁玉华','DYH'); insert into user(id, name, py) values('19','董秋明','DQM'); insert into user(id, name, py) values('20','董政厚','DZH'); insert into user(id, name, py) values('21','杜玉焱','DYZ'); insert into user(id, name, py) values('22','段瑜芝','DZZ'); insert into user(id, name, py) values('23','傅广友','FGY'); insert into user(id, name, py) values('24','傅井飞','FJF'); insert into user(id, name, py) values('25','高辉涛','GHT'); insert into user(id, name, py) values('26','高龙飞','GLF'); insert into user(id, name, py) values('27','高汝英','GRY'); insert into user(id, name, py) values('28','高云天','GYT'); insert into user(id, name, py) values('29','郭义民','GYM'); insert into user(id, name, py) values('30','郭永洪','GYH'); insert into user(id, name, py) values('31','韩国茜','HGZ'); insert into user(id, name, py) values('32','韩龙康','HLK'); insert into user(id, name, py) values('33','韩伟佳','HWJ'); insert into user(id, name, py) values('34','韩扬谦','HYQ'); insert into user(id, name, py) values('35','郝静生','HJS'); insert into user(id, name, py) values('36','何柏红','HBH'); insert into user(id, name, py) values('37','何彩智','HCZ'); insert into user(id, name, py) values('38','何陶增','HTZ'); insert into user(id, name, py) values('39','何薇','HZ'); insert into user(id, name, py) values('40','何小凡','HXF'); insert into user(id, name, py) values('41','何振平','HZP'); insert into user(id, name, py) values('42','洪彩辉','HCH'); insert into user(id, name, py) values('43','胡仕明','HSM'); insert into user(id, name, py) values('44','黄建朋','HJP'); insert into user(id, name, py) values('45','黄祥荣','HXR'); insert into user(id, name, py) values('46','黄璇平','HZP'); insert into user(id, name, py) values('47','贾茂飞','JMF'); insert into user(id, name, py) values('48','李迪茹','LDR'); insert into user(id, name, py) values('49','李桂博','LGB'); insert into user(id, name, py) values('50','李国祯','LGZ'); insert into user(id, name, py) values('51','李宏川','LHC'); insert into user(id, name, py) values('52','李梅','LM'); insert into user(id, name, py) values('53','李媚文','LMW'); insert into user(id, name, py) values('54','李孟惠','LMH'); insert into user(id, name, py) values('55','李南懋','LNZ'); insert into user(id, name, py) values('56','李鹏龙','LPL'); insert into user(id, name, py) values('57','李诗庸','LSY'); insert into user(id, name, py) values('58','李姝勇','LZY'); insert into user(id, name, py) values('59','李树鹏','LSP'); insert into user(id, name, py) values('60','李薇红','LZH'); insert into user(id, name, py) values('61','李文章','LWZ'); insert into user(id, name, py) values('62','李星佳','LXJ'); insert into user(id, name, py) values('63','李兴','LX'); insert into user(id, name, py) values('64','李秀倩','LXZ'); insert into user(id, name, py) values('65','李艳生','LYS'); insert into user(id, name, py) values('66','李燕金','LYJ'); insert into user(id, name, py) values('67','李玉彪','LYB'); insert into user(id, name, py) values('68','李振峰','LZF'); insert into user(id, name, py) values('69','梁斌芳','LBF'); insert into user(id, name, py) values('70','梁国云','LGY'); insert into user(id, name, py) values('71','梁巧爱','LQA'); insert into user(id, name, py) values('72','梁照金','LZJ'); insert into user(id, name, py) values('73','林婧美','LZM'); insert into user(id, name, py) values('74','林沛寿','LPS'); insert into user(id, name, py) values('75','林薇程','LZC'); insert into user(id, name, py) values('76','林伟玉','LWY'); insert into user(id, name, py) values('77','林艺玲','LYL'); insert into user(id, name, py) values('78','刘睿','LR'); insert into user(id, name, py) values('79','刘芊芊','LQQ'); insert into user(id, name, py) values('80','刘海波','LHB'); insert into user(id, name, py) values('81','刘斓琴','LZQ'); insert into user(id, name, py) values('82','刘磊东','LLD'); insert into user(id, name, py) values('83','刘明琪','LMZ'); insert into user(id, name, py) values('84','刘铭恩','LME'); insert into user(id, name, py) values('85','刘任恺','LRZ'); insert into user(id, name, py) values('86','刘水秋','LSQ'); insert into user(id, name, py) values('87','刘文萱','LWZ'); insert into user(id, name, py) values('88','刘祥瑶','LXY'); insert into user(id, name, py) values('89','刘薪坪','LXP'); insert into user(id, name, py) values('90','刘秀涛','LXT'); insert into user(id, name, py) values('91','刘彦利','LYL'); insert into user(id, name, py) values('92','刘益存','LYC'); insert into user(id, name, py) values('93','龙子苹','LZP'); insert into user(id, name, py) values('94','卢秀剑','LXJ'); insert into user(id, name, py) values('95','罗乔华','LQH'); insert into user(id, name, py) values('96','罗希清','LXQ'); insert into user(id, name, py) values('97','马家兰','MJL'); insert into user(id, name, py) values('98','马莲莹','MLY'); insert into user(id, name, py) values('99','马宁文','MNW'); insert into user(id, name, py) values('100','马水鹏','MSP'); insert into user(id, name, py) values('101','孟三云','MSY'); insert into user(id, name, py) values('102','孟寿云','MSY'); insert into user(id, name, py) values('103','聂伟元','NWY'); insert into user(id, name, py) values('104','潘永飞','PYF'); insert into user(id, name, py) values('105','彭健颖','PJY'); insert into user(id, name, py) values('106','钱文松','QWS'); insert into user(id, name, py) values('107','屈江珍','QJZ'); insert into user(id, name, py) values('108','邵建林','SJL'); insert into user(id, name, py) values('109','施家晖','SJZ'); insert into user(id, name, py) values('110','施艺英','SYY'); insert into user(id, name, py) values('111','孙常程','SCC'); insert into user(id, name, py) values('112','谭佳盈','TJY'); insert into user(id, name, py) values('113','唐春珊','TCS'); insert into user(id, name, py) values('114','唐军霞','TJX'); insert into user(id, name, py) values('115','唐里丽','TLL'); insert into user(id, name, py) values('116','陶姐华','TJH'); insert into user(id, name, py) values('117','万圻艳','WZY'); insert into user(id, name, py) values('118','王傲凤','WAF'); insert into user(id, name, py) values('119','王德英','WDY'); insert into user(id, name, py) values('120','王鼎华','WDH'); insert into user(id, name, py) values('121','王慧','WH'); insert into user(id, name, py) values('122','王佳光','WJG'); insert into user(id, name, py) values('123','王家胜','WJS'); insert into user(id, name, py) values('124','王竞飞','WJF'); insert into user(id, name, py) values('125','王科磊','WKL'); insert into user(id, name, py) values('126','王丽章','WLZ'); insert into user(id, name, py) values('127','王励苗','WLM'); insert into user(id, name, py) values('128','王美东','WMD'); insert into user(id, name, py) values('129','王美媛','WMZ'); insert into user(id, name, py) values('130','王蕊颖','WRY'); insert into user(id, name, py) values('131','王士成','WSC'); insert into user(id, name, py) values('132','王熙斌','WXB'); insert into user(id, name, py) values('133','王香军','WXJ'); insert into user(id, name, py) values('134','王休娜','WXN'); insert into user(id, name, py) values('135','王仪行','WYX'); insert into user(id, name, py) values('136','王赢基','WYJ'); insert into user(id, name, py) values('137','王云芯','WYX'); insert into user(id, name, py) values('138','王郑林','WZL'); insert into user(id, name, py) values('139','王治良','WZL'); insert into user(id, name, py) values('140','王忠宇','WZY'); insert into user(id, name, py) values('141','王子冰','WZB'); insert into user(id, name, py) values('142','韦新裕','WXY'); insert into user(id, name, py) values('143','魏复冉','WFR'); insert into user(id, name, py) values('144','吴翰志','WHZ'); insert into user(id, name, py) values('145','吴美森','WMS'); insert into user(id, name, py) values('146','吴翔良','WXL'); insert into user(id, name, py) values('147','吴艳伟','WYW'); insert into user(id, name, py) values('148','吴钲辉','WZH'); insert into user(id, name, py) values('149','向盼洛','XPL'); insert into user(id, name, py) values('150','萧恩','XE'); insert into user(id, name, py) values('151','萧军杰','XJJ'); insert into user(id, name, py) values('152','萧圣梅','XSM'); insert into user(id, name, py) values('153','谢辰吉','XCJ'); insert into user(id, name, py) values('154','徐郎求','XLQ'); insert into user(id, name, py) values('155','徐铭森','XMS'); insert into user(id, name, py) values('156','徐蓉伟','XRW'); insert into user(id, name, py) values('157','许为梧','XWW'); insert into user(id, name, py) values('158','阎皓河','YZH'); insert into user(id, name, py) values('159','阎思华','YSH'); insert into user(id, name, py) values('160','杨爱秀','YAX'); insert into user(id, name, py) values('161','杨昆飞','YKF'); insert into user(id, name, py) values('162','杨良林','YLL'); insert into user(id, name, py) values('163','杨少君','YSJ'); insert into user(id, name, py) values('164','杨玉丽','YYL'); insert into user(id, name, py) values('165','杨之安','YZA'); insert into user(id, name, py) values('166','尤榕锋','YZF'); insert into user(id, name, py) values('167','余俊珠','YJZ'); insert into user(id, name, py) values('168','袁江蔓','YJM'); insert into user(id, name, py) values('169','张必翰','ZBH'); insert into user(id, name, py) values('170','张昌颜','ZCY'); insert into user(id, name, py) values('171','张恩星','ZEX'); insert into user(id, name, py) values('172','张飞强','ZFQ'); insert into user(id, name, py) values('173','张凤焯','ZFZ'); insert into user(id, name, py) values('174','张国强','ZGQ'); insert into user(id, name, py) values('175','张计欣','ZJX'); insert into user(id, name, py) values('176','张家颖','ZJY'); insert into user(id, name, py) values('177','张金安','ZJA'); insert into user(id, name, py) values('178','张莉','ZL'); insert into user(id, name, py) values('179','张米龙','ZML'); insert into user(id, name, py) values('180','张善渊','ZSY'); insert into user(id, name, py) values('181','张万敏','ZWM'); insert into user(id, name, py) values('182','张晓林','ZXL'); insert into user(id, name, py) values('183','张秀高','ZXG'); ================================================ FILE: src/test/resources/oracle/mybatis-config-pagesizezero.xml ================================================ ================================================ FILE: src/test/resources/oracle/mybatis-config-reasonable.xml ================================================ ================================================ FILE: src/test/resources/oracle/mybatis-config-rowbounds.xml ================================================ ================================================ FILE: src/test/resources/oracle/mybatis-config.xml ================================================ ================================================ FILE: src/test/resources/oracle/oracle.sql ================================================ /* * The MIT License (MIT) * * Copyright (c) 2014-2022 abel533@gmail.com * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -- 启用scott/tiger用户的方法 -- 解锁 alter user scott account unlock; -- 重设密码 alter user scott identified by tiger; -- 查看用户状态 -- select username,account_status from dba_users; -- 创建表 create table user ( id number(6), name varchar2(50), py varchar2(50) ); alter table user add constraint PK_USER_ID primary key (ID); -- 插入测试数据 insert into user(id, name, py) values('1','毕淑儒','BSR'); insert into user(id, name, py) values('2','蔡兴熙','CXX'); insert into user(id, name, py) values('3','曾三杰','ZSJ'); insert into user(id, name, py) values('4','常元琴','CYQ'); insert into user(id, name, py) values('5','陈栋芬','CDF'); insert into user(id, name, py) values('6','陈宁婷','CNZ'); insert into user(id, name, py) values('7','陈瑞','CR'); insert into user(id, name, py) values('8','陈武宵','CWX'); insert into user(id, name, py) values('9','陈晓丽','CXL'); insert into user(id, name, py) values('10','陈翼涛','CYT'); insert into user(id, name, py) values('11','陈宇然','CYR'); insert into user(id, name, py) values('12','陈震','CZ'); insert into user(id, name, py) values('13','程太君','CTJ'); insert into user(id, name, py) values('14','程玉娜','CYN'); insert into user(id, name, py) values('15','丛贺轩','CHX'); insert into user(id, name, py) values('16','戴国宇','DGY'); insert into user(id, name, py) values('17','戴杰亮','DJL'); insert into user(id, name, py) values('18','丁玉华','DYH'); insert into user(id, name, py) values('19','董秋明','DQM'); insert into user(id, name, py) values('20','董政厚','DZH'); insert into user(id, name, py) values('21','杜玉焱','DYZ'); insert into user(id, name, py) values('22','段瑜芝','DZZ'); insert into user(id, name, py) values('23','傅广友','FGY'); insert into user(id, name, py) values('24','傅井飞','FJF'); insert into user(id, name, py) values('25','高辉涛','GHT'); insert into user(id, name, py) values('26','高龙飞','GLF'); insert into user(id, name, py) values('27','高汝英','GRY'); insert into user(id, name, py) values('28','高云天','GYT'); insert into user(id, name, py) values('29','郭义民','GYM'); insert into user(id, name, py) values('30','郭永洪','GYH'); insert into user(id, name, py) values('31','韩国茜','HGZ'); insert into user(id, name, py) values('32','韩龙康','HLK'); insert into user(id, name, py) values('33','韩伟佳','HWJ'); insert into user(id, name, py) values('34','韩扬谦','HYQ'); insert into user(id, name, py) values('35','郝静生','HJS'); insert into user(id, name, py) values('36','何柏红','HBH'); insert into user(id, name, py) values('37','何彩智','HCZ'); insert into user(id, name, py) values('38','何陶增','HTZ'); insert into user(id, name, py) values('39','何薇','HZ'); insert into user(id, name, py) values('40','何小凡','HXF'); insert into user(id, name, py) values('41','何振平','HZP'); insert into user(id, name, py) values('42','洪彩辉','HCH'); insert into user(id, name, py) values('43','胡仕明','HSM'); insert into user(id, name, py) values('44','黄建朋','HJP'); insert into user(id, name, py) values('45','黄祥荣','HXR'); insert into user(id, name, py) values('46','黄璇平','HZP'); insert into user(id, name, py) values('47','贾茂飞','JMF'); insert into user(id, name, py) values('48','李迪茹','LDR'); insert into user(id, name, py) values('49','李桂博','LGB'); insert into user(id, name, py) values('50','李国祯','LGZ'); insert into user(id, name, py) values('51','李宏川','LHC'); insert into user(id, name, py) values('52','李梅','LM'); insert into user(id, name, py) values('53','李媚文','LMW'); insert into user(id, name, py) values('54','李孟惠','LMH'); insert into user(id, name, py) values('55','李南懋','LNZ'); insert into user(id, name, py) values('56','李鹏龙','LPL'); insert into user(id, name, py) values('57','李诗庸','LSY'); insert into user(id, name, py) values('58','李姝勇','LZY'); insert into user(id, name, py) values('59','李树鹏','LSP'); insert into user(id, name, py) values('60','李薇红','LZH'); insert into user(id, name, py) values('61','李文章','LWZ'); insert into user(id, name, py) values('62','李星佳','LXJ'); insert into user(id, name, py) values('63','李兴','LX'); insert into user(id, name, py) values('64','李秀倩','LXZ'); insert into user(id, name, py) values('65','李艳生','LYS'); insert into user(id, name, py) values('66','李燕金','LYJ'); insert into user(id, name, py) values('67','李玉彪','LYB'); insert into user(id, name, py) values('68','李振峰','LZF'); insert into user(id, name, py) values('69','梁斌芳','LBF'); insert into user(id, name, py) values('70','梁国云','LGY'); insert into user(id, name, py) values('71','梁巧爱','LQA'); insert into user(id, name, py) values('72','梁照金','LZJ'); insert into user(id, name, py) values('73','林婧美','LZM'); insert into user(id, name, py) values('74','林沛寿','LPS'); insert into user(id, name, py) values('75','林薇程','LZC'); insert into user(id, name, py) values('76','林伟玉','LWY'); insert into user(id, name, py) values('77','林艺玲','LYL'); insert into user(id, name, py) values('78','刘睿','LR'); insert into user(id, name, py) values('79','刘芊芊','LQQ'); insert into user(id, name, py) values('80','刘海波','LHB'); insert into user(id, name, py) values('81','刘斓琴','LZQ'); insert into user(id, name, py) values('82','刘磊东','LLD'); insert into user(id, name, py) values('83','刘明琪','LMZ'); insert into user(id, name, py) values('84','刘铭恩','LME'); insert into user(id, name, py) values('85','刘任恺','LRZ'); insert into user(id, name, py) values('86','刘水秋','LSQ'); insert into user(id, name, py) values('87','刘文萱','LWZ'); insert into user(id, name, py) values('88','刘祥瑶','LXY'); insert into user(id, name, py) values('89','刘薪坪','LXP'); insert into user(id, name, py) values('90','刘秀涛','LXT'); insert into user(id, name, py) values('91','刘彦利','LYL'); insert into user(id, name, py) values('92','刘益存','LYC'); insert into user(id, name, py) values('93','龙子苹','LZP'); insert into user(id, name, py) values('94','卢秀剑','LXJ'); insert into user(id, name, py) values('95','罗乔华','LQH'); insert into user(id, name, py) values('96','罗希清','LXQ'); insert into user(id, name, py) values('97','马家兰','MJL'); insert into user(id, name, py) values('98','马莲莹','MLY'); insert into user(id, name, py) values('99','马宁文','MNW'); insert into user(id, name, py) values('100','马水鹏','MSP'); insert into user(id, name, py) values('101','孟三云','MSY'); insert into user(id, name, py) values('102','孟寿云','MSY'); insert into user(id, name, py) values('103','聂伟元','NWY'); insert into user(id, name, py) values('104','潘永飞','PYF'); insert into user(id, name, py) values('105','彭健颖','PJY'); insert into user(id, name, py) values('106','钱文松','QWS'); insert into user(id, name, py) values('107','屈江珍','QJZ'); insert into user(id, name, py) values('108','邵建林','SJL'); insert into user(id, name, py) values('109','施家晖','SJZ'); insert into user(id, name, py) values('110','施艺英','SYY'); insert into user(id, name, py) values('111','孙常程','SCC'); insert into user(id, name, py) values('112','谭佳盈','TJY'); insert into user(id, name, py) values('113','唐春珊','TCS'); insert into user(id, name, py) values('114','唐军霞','TJX'); insert into user(id, name, py) values('115','唐里丽','TLL'); insert into user(id, name, py) values('116','陶姐华','TJH'); insert into user(id, name, py) values('117','万圻艳','WZY'); insert into user(id, name, py) values('118','王傲凤','WAF'); insert into user(id, name, py) values('119','王德英','WDY'); insert into user(id, name, py) values('120','王鼎华','WDH'); insert into user(id, name, py) values('121','王慧','WH'); insert into user(id, name, py) values('122','王佳光','WJG'); insert into user(id, name, py) values('123','王家胜','WJS'); insert into user(id, name, py) values('124','王竞飞','WJF'); insert into user(id, name, py) values('125','王科磊','WKL'); insert into user(id, name, py) values('126','王丽章','WLZ'); insert into user(id, name, py) values('127','王励苗','WLM'); insert into user(id, name, py) values('128','王美东','WMD'); insert into user(id, name, py) values('129','王美媛','WMZ'); insert into user(id, name, py) values('130','王蕊颖','WRY'); insert into user(id, name, py) values('131','王士成','WSC'); insert into user(id, name, py) values('132','王熙斌','WXB'); insert into user(id, name, py) values('133','王香军','WXJ'); insert into user(id, name, py) values('134','王休娜','WXN'); insert into user(id, name, py) values('135','王仪行','WYX'); insert into user(id, name, py) values('136','王赢基','WYJ'); insert into user(id, name, py) values('137','王云芯','WYX'); insert into user(id, name, py) values('138','王郑林','WZL'); insert into user(id, name, py) values('139','王治良','WZL'); insert into user(id, name, py) values('140','王忠宇','WZY'); insert into user(id, name, py) values('141','王子冰','WZB'); insert into user(id, name, py) values('142','韦新裕','WXY'); insert into user(id, name, py) values('143','魏复冉','WFR'); insert into user(id, name, py) values('144','吴翰志','WHZ'); insert into user(id, name, py) values('145','吴美森','WMS'); insert into user(id, name, py) values('146','吴翔良','WXL'); insert into user(id, name, py) values('147','吴艳伟','WYW'); insert into user(id, name, py) values('148','吴钲辉','WZH'); insert into user(id, name, py) values('149','向盼洛','XPL'); insert into user(id, name, py) values('150','萧恩','XE'); insert into user(id, name, py) values('151','萧军杰','XJJ'); insert into user(id, name, py) values('152','萧圣梅','XSM'); insert into user(id, name, py) values('153','谢辰吉','XCJ'); insert into user(id, name, py) values('154','徐郎求','XLQ'); insert into user(id, name, py) values('155','徐铭森','XMS'); insert into user(id, name, py) values('156','徐蓉伟','XRW'); insert into user(id, name, py) values('157','许为梧','XWW'); insert into user(id, name, py) values('158','阎皓河','YZH'); insert into user(id, name, py) values('159','阎思华','YSH'); insert into user(id, name, py) values('160','杨爱秀','YAX'); insert into user(id, name, py) values('161','杨昆飞','YKF'); insert into user(id, name, py) values('162','杨良林','YLL'); insert into user(id, name, py) values('163','杨少君','YSJ'); insert into user(id, name, py) values('164','杨玉丽','YYL'); insert into user(id, name, py) values('165','杨之安','YZA'); insert into user(id, name, py) values('166','尤榕锋','YZF'); insert into user(id, name, py) values('167','余俊珠','YJZ'); insert into user(id, name, py) values('168','袁江蔓','YJM'); insert into user(id, name, py) values('169','张必翰','ZBH'); insert into user(id, name, py) values('170','张昌颜','ZCY'); insert into user(id, name, py) values('171','张恩星','ZEX'); insert into user(id, name, py) values('172','张飞强','ZFQ'); insert into user(id, name, py) values('173','张凤焯','ZFZ'); insert into user(id, name, py) values('174','张国强','ZGQ'); insert into user(id, name, py) values('175','张计欣','ZJX'); insert into user(id, name, py) values('176','张家颖','ZJY'); insert into user(id, name, py) values('177','张金安','ZJA'); insert into user(id, name, py) values('178','张莉','ZL'); insert into user(id, name, py) values('179','张米龙','ZML'); insert into user(id, name, py) values('180','张善渊','ZSY'); insert into user(id, name, py) values('181','张万敏','ZWM'); insert into user(id, name, py) values('182','张晓林','ZXL'); insert into user(id, name, py) values('183','张秀高','ZXG'); ================================================ FILE: src/test/resources/postgresql/mybatis-config-pagesizezero.xml ================================================ ================================================ FILE: src/test/resources/postgresql/mybatis-config-reasonable.xml ================================================ ================================================ FILE: src/test/resources/postgresql/mybatis-config-rowbounds.xml ================================================ ================================================ FILE: src/test/resources/postgresql/mybatis-config.xml ================================================ ================================================ FILE: src/test/resources/postgresql/postgresql.sql ================================================ /* * The MIT License (MIT) * * Copyright (c) 2014-2022 abel533@gmail.com * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ create USER pagehelper WITH PASSWORD 'pagehelper'; create DATABASE pagehelper OWNER pagehelper; GRANT ALL PRIVILEGES ON DATABASE pagehelper to pagehelper; CREATE TABLE user ( id SERIAL, name varchar(50) DEFAULT NULL, py varchar(50) DEFAULT NULL, PRIMARY KEY (Id) ); ALTER TABLE user OWNER TO pagehelper; insert into user(id, name, py) values('1','毕淑儒','BSR'); insert into user(id, name, py) values('2','蔡兴熙','CXX'); insert into user(id, name, py) values('3','曾三杰','ZSJ'); insert into user(id, name, py) values('4','常元琴','CYQ'); insert into user(id, name, py) values('5','陈栋芬','CDF'); insert into user(id, name, py) values('6','陈宁婷','CNZ'); insert into user(id, name, py) values('7','陈瑞','CR'); insert into user(id, name, py) values('8','陈武宵','CWX'); insert into user(id, name, py) values('9','陈晓丽','CXL'); insert into user(id, name, py) values('10','陈翼涛','CYT'); insert into user(id, name, py) values('11','陈宇然','CYR'); insert into user(id, name, py) values('12','陈震','CZ'); insert into user(id, name, py) values('13','程太君','CTJ'); insert into user(id, name, py) values('14','程玉娜','CYN'); insert into user(id, name, py) values('15','丛贺轩','CHX'); insert into user(id, name, py) values('16','戴国宇','DGY'); insert into user(id, name, py) values('17','戴杰亮','DJL'); insert into user(id, name, py) values('18','丁玉华','DYH'); insert into user(id, name, py) values('19','董秋明','DQM'); insert into user(id, name, py) values('20','董政厚','DZH'); insert into user(id, name, py) values('21','杜玉焱','DYZ'); insert into user(id, name, py) values('22','段瑜芝','DZZ'); insert into user(id, name, py) values('23','傅广友','FGY'); insert into user(id, name, py) values('24','傅井飞','FJF'); insert into user(id, name, py) values('25','高辉涛','GHT'); insert into user(id, name, py) values('26','高龙飞','GLF'); insert into user(id, name, py) values('27','高汝英','GRY'); insert into user(id, name, py) values('28','高云天','GYT'); insert into user(id, name, py) values('29','郭义民','GYM'); insert into user(id, name, py) values('30','郭永洪','GYH'); insert into user(id, name, py) values('31','韩国茜','HGZ'); insert into user(id, name, py) values('32','韩龙康','HLK'); insert into user(id, name, py) values('33','韩伟佳','HWJ'); insert into user(id, name, py) values('34','韩扬谦','HYQ'); insert into user(id, name, py) values('35','郝静生','HJS'); insert into user(id, name, py) values('36','何柏红','HBH'); insert into user(id, name, py) values('37','何彩智','HCZ'); insert into user(id, name, py) values('38','何陶增','HTZ'); insert into user(id, name, py) values('39','何薇','HZ'); insert into user(id, name, py) values('40','何小凡','HXF'); insert into user(id, name, py) values('41','何振平','HZP'); insert into user(id, name, py) values('42','洪彩辉','HCH'); insert into user(id, name, py) values('43','胡仕明','HSM'); insert into user(id, name, py) values('44','黄建朋','HJP'); insert into user(id, name, py) values('45','黄祥荣','HXR'); insert into user(id, name, py) values('46','黄璇平','HZP'); insert into user(id, name, py) values('47','贾茂飞','JMF'); insert into user(id, name, py) values('48','李迪茹','LDR'); insert into user(id, name, py) values('49','李桂博','LGB'); insert into user(id, name, py) values('50','李国祯','LGZ'); insert into user(id, name, py) values('51','李宏川','LHC'); insert into user(id, name, py) values('52','李梅','LM'); insert into user(id, name, py) values('53','李媚文','LMW'); insert into user(id, name, py) values('54','李孟惠','LMH'); insert into user(id, name, py) values('55','李南懋','LNZ'); insert into user(id, name, py) values('56','李鹏龙','LPL'); insert into user(id, name, py) values('57','李诗庸','LSY'); insert into user(id, name, py) values('58','李姝勇','LZY'); insert into user(id, name, py) values('59','李树鹏','LSP'); insert into user(id, name, py) values('60','李薇红','LZH'); insert into user(id, name, py) values('61','李文章','LWZ'); insert into user(id, name, py) values('62','李星佳','LXJ'); insert into user(id, name, py) values('63','李兴','LX'); insert into user(id, name, py) values('64','李秀倩','LXZ'); insert into user(id, name, py) values('65','李艳生','LYS'); insert into user(id, name, py) values('66','李燕金','LYJ'); insert into user(id, name, py) values('67','李玉彪','LYB'); insert into user(id, name, py) values('68','李振峰','LZF'); insert into user(id, name, py) values('69','梁斌芳','LBF'); insert into user(id, name, py) values('70','梁国云','LGY'); insert into user(id, name, py) values('71','梁巧爱','LQA'); insert into user(id, name, py) values('72','梁照金','LZJ'); insert into user(id, name, py) values('73','林婧美','LZM'); insert into user(id, name, py) values('74','林沛寿','LPS'); insert into user(id, name, py) values('75','林薇程','LZC'); insert into user(id, name, py) values('76','林伟玉','LWY'); insert into user(id, name, py) values('77','林艺玲','LYL'); insert into user(id, name, py) values('78','刘睿','LR'); insert into user(id, name, py) values('79','刘芊芊','LQQ'); insert into user(id, name, py) values('80','刘海波','LHB'); insert into user(id, name, py) values('81','刘斓琴','LZQ'); insert into user(id, name, py) values('82','刘磊东','LLD'); insert into user(id, name, py) values('83','刘明琪','LMZ'); insert into user(id, name, py) values('84','刘铭恩','LME'); insert into user(id, name, py) values('85','刘任恺','LRZ'); insert into user(id, name, py) values('86','刘水秋','LSQ'); insert into user(id, name, py) values('87','刘文萱','LWZ'); insert into user(id, name, py) values('88','刘祥瑶','LXY'); insert into user(id, name, py) values('89','刘薪坪','LXP'); insert into user(id, name, py) values('90','刘秀涛','LXT'); insert into user(id, name, py) values('91','刘彦利','LYL'); insert into user(id, name, py) values('92','刘益存','LYC'); insert into user(id, name, py) values('93','龙子苹','LZP'); insert into user(id, name, py) values('94','卢秀剑','LXJ'); insert into user(id, name, py) values('95','罗乔华','LQH'); insert into user(id, name, py) values('96','罗希清','LXQ'); insert into user(id, name, py) values('97','马家兰','MJL'); insert into user(id, name, py) values('98','马莲莹','MLY'); insert into user(id, name, py) values('99','马宁文','MNW'); insert into user(id, name, py) values('100','马水鹏','MSP'); insert into user(id, name, py) values('101','孟三云','MSY'); insert into user(id, name, py) values('102','孟寿云','MSY'); insert into user(id, name, py) values('103','聂伟元','NWY'); insert into user(id, name, py) values('104','潘永飞','PYF'); insert into user(id, name, py) values('105','彭健颖','PJY'); insert into user(id, name, py) values('106','钱文松','QWS'); insert into user(id, name, py) values('107','屈江珍','QJZ'); insert into user(id, name, py) values('108','邵建林','SJL'); insert into user(id, name, py) values('109','施家晖','SJZ'); insert into user(id, name, py) values('110','施艺英','SYY'); insert into user(id, name, py) values('111','孙常程','SCC'); insert into user(id, name, py) values('112','谭佳盈','TJY'); insert into user(id, name, py) values('113','唐春珊','TCS'); insert into user(id, name, py) values('114','唐军霞','TJX'); insert into user(id, name, py) values('115','唐里丽','TLL'); insert into user(id, name, py) values('116','陶姐华','TJH'); insert into user(id, name, py) values('117','万圻艳','WZY'); insert into user(id, name, py) values('118','王傲凤','WAF'); insert into user(id, name, py) values('119','王德英','WDY'); insert into user(id, name, py) values('120','王鼎华','WDH'); insert into user(id, name, py) values('121','王慧','WH'); insert into user(id, name, py) values('122','王佳光','WJG'); insert into user(id, name, py) values('123','王家胜','WJS'); insert into user(id, name, py) values('124','王竞飞','WJF'); insert into user(id, name, py) values('125','王科磊','WKL'); insert into user(id, name, py) values('126','王丽章','WLZ'); insert into user(id, name, py) values('127','王励苗','WLM'); insert into user(id, name, py) values('128','王美东','WMD'); insert into user(id, name, py) values('129','王美媛','WMZ'); insert into user(id, name, py) values('130','王蕊颖','WRY'); insert into user(id, name, py) values('131','王士成','WSC'); insert into user(id, name, py) values('132','王熙斌','WXB'); insert into user(id, name, py) values('133','王香军','WXJ'); insert into user(id, name, py) values('134','王休娜','WXN'); insert into user(id, name, py) values('135','王仪行','WYX'); insert into user(id, name, py) values('136','王赢基','WYJ'); insert into user(id, name, py) values('137','王云芯','WYX'); insert into user(id, name, py) values('138','王郑林','WZL'); insert into user(id, name, py) values('139','王治良','WZL'); insert into user(id, name, py) values('140','王忠宇','WZY'); insert into user(id, name, py) values('141','王子冰','WZB'); insert into user(id, name, py) values('142','韦新裕','WXY'); insert into user(id, name, py) values('143','魏复冉','WFR'); insert into user(id, name, py) values('144','吴翰志','WHZ'); insert into user(id, name, py) values('145','吴美森','WMS'); insert into user(id, name, py) values('146','吴翔良','WXL'); insert into user(id, name, py) values('147','吴艳伟','WYW'); insert into user(id, name, py) values('148','吴钲辉','WZH'); insert into user(id, name, py) values('149','向盼洛','XPL'); insert into user(id, name, py) values('150','萧恩','XE'); insert into user(id, name, py) values('151','萧军杰','XJJ'); insert into user(id, name, py) values('152','萧圣梅','XSM'); insert into user(id, name, py) values('153','谢辰吉','XCJ'); insert into user(id, name, py) values('154','徐郎求','XLQ'); insert into user(id, name, py) values('155','徐铭森','XMS'); insert into user(id, name, py) values('156','徐蓉伟','XRW'); insert into user(id, name, py) values('157','许为梧','XWW'); insert into user(id, name, py) values('158','阎皓河','YZH'); insert into user(id, name, py) values('159','阎思华','YSH'); insert into user(id, name, py) values('160','杨爱秀','YAX'); insert into user(id, name, py) values('161','杨昆飞','YKF'); insert into user(id, name, py) values('162','杨良林','YLL'); insert into user(id, name, py) values('163','杨少君','YSJ'); insert into user(id, name, py) values('164','杨玉丽','YYL'); insert into user(id, name, py) values('165','杨之安','YZA'); insert into user(id, name, py) values('166','尤榕锋','YZF'); insert into user(id, name, py) values('167','余俊珠','YJZ'); insert into user(id, name, py) values('168','袁江蔓','YJM'); insert into user(id, name, py) values('169','张必翰','ZBH'); insert into user(id, name, py) values('170','张昌颜','ZCY'); insert into user(id, name, py) values('171','张恩星','ZEX'); insert into user(id, name, py) values('172','张飞强','ZFQ'); insert into user(id, name, py) values('173','张凤焯','ZFZ'); insert into user(id, name, py) values('174','张国强','ZGQ'); insert into user(id, name, py) values('175','张计欣','ZJX'); insert into user(id, name, py) values('176','张家颖','ZJY'); insert into user(id, name, py) values('177','张金安','ZJA'); insert into user(id, name, py) values('178','张莉','ZL'); insert into user(id, name, py) values('179','张米龙','ZML'); insert into user(id, name, py) values('180','张善渊','ZSY'); insert into user(id, name, py) values('181','张万敏','ZWM'); insert into user(id, name, py) values('182','张晓林','ZXL'); insert into user(id, name, py) values('183','张秀高','ZXG'); ================================================ FILE: src/test/resources/rowbounds/hsqldb.sql ================================================ /* * The MIT License (MIT) * * Copyright (c) 2014-2022 abel533@gmail.com * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ drop table user if exists; create table user ( id integer, name varchar(32), py varchar(5) ); insert into user(id, name, py) values ('1', '毕淑儒', 'BSR'); insert into user(id, name, py) values('2','蔡兴熙','CXX'); insert into user(id, name, py) values('3','曾三杰','ZSJ'); insert into user(id, name, py) values('4','常元琴','CYQ'); insert into user(id, name, py) values('5','陈栋芬','CDF'); insert into user(id, name, py) values('6','陈宁婷','CNZ'); insert into user(id, name, py) values('7','陈瑞','CR'); insert into user(id, name, py) values('8','陈武宵','CWX'); insert into user(id, name, py) values('9','陈晓丽','CXL'); insert into user(id, name, py) values('10','陈翼涛','CYT'); insert into user(id, name, py) values('11','陈宇然','CYR'); insert into user(id, name, py) values('12','陈震','CZ'); insert into user(id, name, py) values('13','程太君','CTJ'); insert into user(id, name, py) values('14','程玉娜','CYN'); insert into user(id, name, py) values('15','丛贺轩','CHX'); insert into user(id, name, py) values('16','戴国宇','DGY'); insert into user(id, name, py) values('17','戴杰亮','DJL'); insert into user(id, name, py) values('18','丁玉华','DYH'); insert into user(id, name, py) values('19','董秋明','DQM'); insert into user(id, name, py) values('20','董政厚','DZH'); insert into user(id, name, py) values('21','杜玉焱','DYZ'); insert into user(id, name, py) values('22','段瑜芝','DZZ'); insert into user(id, name, py) values('23','傅广友','FGY'); insert into user(id, name, py) values('24','傅井飞','FJF'); insert into user(id, name, py) values('25','高辉涛','GHT'); insert into user(id, name, py) values('26','高龙飞','GLF'); insert into user(id, name, py) values('27','高汝英','GRY'); insert into user(id, name, py) values('28','高云天','GYT'); insert into user(id, name, py) values('29','郭义民','GYM'); insert into user(id, name, py) values('30','郭永洪','GYH'); insert into user(id, name, py) values('31','韩国茜','HGZ'); insert into user(id, name, py) values('32','韩龙康','HLK'); insert into user(id, name, py) values('33','韩伟佳','HWJ'); insert into user(id, name, py) values('34','韩扬谦','HYQ'); insert into user(id, name, py) values('35','郝静生','HJS'); insert into user(id, name, py) values('36','何柏红','HBH'); insert into user(id, name, py) values('37','何彩智','HCZ'); insert into user(id, name, py) values('38','何陶增','HTZ'); insert into user(id, name, py) values('39','何薇','HZ'); insert into user(id, name, py) values('40','何小凡','HXF'); insert into user(id, name, py) values('41','何振平','HZP'); insert into user(id, name, py) values('42','洪彩辉','HCH'); insert into user(id, name, py) values('43','胡仕明','HSM'); insert into user(id, name, py) values('44','黄建朋','HJP'); insert into user(id, name, py) values('45','黄祥荣','HXR'); insert into user(id, name, py) values('46','黄璇平','HZP'); insert into user(id, name, py) values('47','贾茂飞','JMF'); insert into user(id, name, py) values('48','李迪茹','LDR'); insert into user(id, name, py) values('49','李桂博','LGB'); insert into user(id, name, py) values('50','李国祯','LGZ'); insert into user(id, name, py) values('51','李宏川','LHC'); insert into user(id, name, py) values('52','李梅','LM'); insert into user(id, name, py) values('53','李媚文','LMW'); insert into user(id, name, py) values('54','李孟惠','LMH'); insert into user(id, name, py) values('55','李南懋','LNZ'); insert into user(id, name, py) values('56','李鹏龙','LPL'); insert into user(id, name, py) values('57','李诗庸','LSY'); insert into user(id, name, py) values('58','李姝勇','LZY'); insert into user(id, name, py) values('59','李树鹏','LSP'); insert into user(id, name, py) values('60','李薇红','LZH'); insert into user(id, name, py) values('61','李文章','LWZ'); insert into user(id, name, py) values('62','李星佳','LXJ'); insert into user(id, name, py) values('63','李兴','LX'); insert into user(id, name, py) values('64','李秀倩','LXZ'); insert into user(id, name, py) values('65','李艳生','LYS'); insert into user(id, name, py) values('66','李燕金','LYJ'); insert into user(id, name, py) values('67','李玉彪','LYB'); insert into user(id, name, py) values('68','李振峰','LZF'); insert into user(id, name, py) values('69','梁斌芳','LBF'); insert into user(id, name, py) values('70','梁国云','LGY'); insert into user(id, name, py) values('71','梁巧爱','LQA'); insert into user(id, name, py) values('72','梁照金','LZJ'); insert into user(id, name, py) values('73','林婧美','LZM'); insert into user(id, name, py) values('74','林沛寿','LPS'); insert into user(id, name, py) values('75','林薇程','LZC'); insert into user(id, name, py) values('76','林伟玉','LWY'); insert into user(id, name, py) values('77','林艺玲','LYL'); insert into user(id, name, py) values('78','刘睿','LR'); insert into user(id, name, py) values('79','刘芊芊','LQQ'); insert into user(id, name, py) values('80','刘海波','LHB'); insert into user(id, name, py) values('81','刘斓琴','LZQ'); insert into user(id, name, py) values('82','刘磊东','LLD'); insert into user(id, name, py) values('83','刘明琪','LMZ'); insert into user(id, name, py) values('84','刘铭恩','LME'); insert into user(id, name, py) values('85','刘任恺','LRZ'); insert into user(id, name, py) values('86','刘水秋','LSQ'); insert into user(id, name, py) values('87','刘文萱','LWZ'); insert into user(id, name, py) values('88','刘祥瑶','LXY'); insert into user(id, name, py) values('89','刘薪坪','LXP'); insert into user(id, name, py) values('90','刘秀涛','LXT'); insert into user(id, name, py) values('91','刘彦利','LYL'); insert into user(id, name, py) values('92','刘益存','LYC'); insert into user(id, name, py) values('93','龙子苹','LZP'); insert into user(id, name, py) values('94','卢秀剑','LXJ'); insert into user(id, name, py) values('95','罗乔华','LQH'); insert into user(id, name, py) values('96','罗希清','LXQ'); insert into user(id, name, py) values('97','马家兰','MJL'); insert into user(id, name, py) values('98','马莲莹','MLY'); insert into user(id, name, py) values('99','马宁文','MNW'); insert into user(id, name, py) values('100','马水鹏','MSP'); insert into user(id, name, py) values('101','孟三云','MSY'); insert into user(id, name, py) values('102','孟寿云','MSY'); insert into user(id, name, py) values('103','聂伟元','NWY'); insert into user(id, name, py) values('104','潘永飞','PYF'); insert into user(id, name, py) values('105','彭健颖','PJY'); insert into user(id, name, py) values('106','钱文松','QWS'); insert into user(id, name, py) values('107','屈江珍','QJZ'); insert into user(id, name, py) values('108','邵建林','SJL'); insert into user(id, name, py) values('109','施家晖','SJZ'); insert into user(id, name, py) values('110','施艺英','SYY'); insert into user(id, name, py) values('111','孙常程','SCC'); insert into user(id, name, py) values('112','谭佳盈','TJY'); insert into user(id, name, py) values('113','唐春珊','TCS'); insert into user(id, name, py) values('114','唐军霞','TJX'); insert into user(id, name, py) values('115','唐里丽','TLL'); insert into user(id, name, py) values('116','陶姐华','TJH'); insert into user(id, name, py) values('117','万圻艳','WZY'); insert into user(id, name, py) values('118','王傲凤','WAF'); insert into user(id, name, py) values('119','王德英','WDY'); insert into user(id, name, py) values('120','王鼎华','WDH'); insert into user(id, name, py) values('121','王慧','WH'); insert into user(id, name, py) values('122','王佳光','WJG'); insert into user(id, name, py) values('123','王家胜','WJS'); insert into user(id, name, py) values('124','王竞飞','WJF'); insert into user(id, name, py) values('125','王科磊','WKL'); insert into user(id, name, py) values('126','王丽章','WLZ'); insert into user(id, name, py) values('127','王励苗','WLM'); insert into user(id, name, py) values('128','王美东','WMD'); insert into user(id, name, py) values('129','王美媛','WMZ'); insert into user(id, name, py) values('130','王蕊颖','WRY'); insert into user(id, name, py) values('131','王士成','WSC'); insert into user(id, name, py) values('132','王熙斌','WXB'); insert into user(id, name, py) values('133','王香军','WXJ'); insert into user(id, name, py) values('134','王休娜','WXN'); insert into user(id, name, py) values('135','王仪行','WYX'); insert into user(id, name, py) values('136','王赢基','WYJ'); insert into user(id, name, py) values('137','王云芯','WYX'); insert into user(id, name, py) values('138','王郑林','WZL'); insert into user(id, name, py) values('139','王治良','WZL'); insert into user(id, name, py) values('140','王忠宇','WZY'); insert into user(id, name, py) values('141','王子冰','WZB'); insert into user(id, name, py) values('142','韦新裕','WXY'); insert into user(id, name, py) values('143','魏复冉','WFR'); insert into user(id, name, py) values('144','吴翰志','WHZ'); insert into user(id, name, py) values('145','吴美森','WMS'); insert into user(id, name, py) values('146','吴翔良','WXL'); insert into user(id, name, py) values('147','吴艳伟','WYW'); insert into user(id, name, py) values('148','吴钲辉','WZH'); insert into user(id, name, py) values('149','向盼洛','XPL'); insert into user(id, name, py) values('150','萧恩','XE'); insert into user(id, name, py) values('151','萧军杰','XJJ'); insert into user(id, name, py) values('152','萧圣梅','XSM'); insert into user(id, name, py) values('153','谢辰吉','XCJ'); insert into user(id, name, py) values('154','徐郎求','XLQ'); insert into user(id, name, py) values('155','徐铭森','XMS'); insert into user(id, name, py) values('156','徐蓉伟','XRW'); insert into user(id, name, py) values('157','许为梧','XWW'); insert into user(id, name, py) values('158','阎皓河','YZH'); insert into user(id, name, py) values('159','阎思华','YSH'); insert into user(id, name, py) values('160','杨爱秀','YAX'); insert into user(id, name, py) values('161','杨昆飞','YKF'); insert into user(id, name, py) values('162','杨良林','YLL'); insert into user(id, name, py) values('163','杨少君','YSJ'); insert into user(id, name, py) values('164','杨玉丽','YYL'); insert into user(id, name, py) values('165','杨之安','YZA'); insert into user(id, name, py) values('166','尤榕锋','YZF'); insert into user(id, name, py) values('167','余俊珠','YJZ'); insert into user(id, name, py) values('168','袁江蔓','YJM'); insert into user(id, name, py) values('169','张必翰','ZBH'); insert into user(id, name, py) values('170','张昌颜','ZCY'); insert into user(id, name, py) values('171','张恩星','ZEX'); insert into user(id, name, py) values('172','张飞强','ZFQ'); insert into user(id, name, py) values('173','张凤焯','ZFZ'); insert into user(id, name, py) values('174','张国强','ZGQ'); insert into user(id, name, py) values('175','张计欣','ZJX'); insert into user(id, name, py) values('176','张家颖','ZJY'); insert into user(id, name, py) values('177','张金安','ZJA'); insert into user(id, name, py) values('178','张莉','ZL'); insert into user(id, name, py) values('179','张米龙','ZML'); insert into user(id, name, py) values('180','张善渊','ZSY'); insert into user(id, name, py) values('181','张万敏','ZWM'); insert into user(id, name, py) values('182','张晓林','ZXL'); insert into user(id, name, py) values('183','张秀高','ZXG'); ================================================ FILE: src/test/resources/rowbounds/mybatis-config.xml ================================================ ================================================ FILE: src/test/resources/sqlserver/mybatis-config-pagesizezero.xml ================================================ ================================================ FILE: src/test/resources/sqlserver/mybatis-config-reasonable.xml ================================================ ================================================ FILE: src/test/resources/sqlserver/mybatis-config-rowbounds.xml ================================================ ================================================ FILE: src/test/resources/sqlserver/mybatis-config.xml ================================================ ================================================ FILE: src/test/resources/test.properties ================================================ # # The MIT License (MIT) # # Copyright (c) 2014-2023 abel533@gmail.com # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. # #\u9996\u5148\u9700\u8981\u5728\u672C\u673A\u914D\u7F6E\u5BF9\u5E94\u7684\u6570\u636E\u5E93 #\u60F3\u8981\u6D4B\u8BD5\u90A3\u4E2A\u6570\u636E\u5E93\uFF0C\u8FD9\u91CC\u5C31\u5199\u90A3\u4E2A\u6570\u636E\u5E93 #\u8FD9\u4E2A\u503C\u548Ctest/resources\u4E2D\u7684\u6570\u636E\u5E93\u5BF9\u5E94\u7684\u6587\u4EF6\u5939\u540D\u5B57\u76F8\u540C #\u76EE\u524D\u53EF\u9009\u4E3A: #hsqldb #mysql #mariadb - \u6CE8\u610F\u6D4B\u8BD5\u4E2D\u7684\u7AEF\u53E3\u662F3309(\u56E0\u4E3A\u9ED8\u8BA4\u548Cmysql\u662F\u4E00\u6837\u7684) #oracle #postgresql #sqlserver #db2 #informix - \u4E0D\u5305\u542Binformix\u7684\u914D\u7F6E\uFF0C\u4E0D\u652F\u6301\u6D4B\u8BD5 #h2 #derby database = hsqldb ================================================ FILE: src/test/resources/xugu/mybatis-config-interceptor.xml ================================================ ================================================ FILE: src/test/resources/xugu/mybatis-config-pagesizezero.xml ================================================ ================================================ FILE: src/test/resources/xugu/mybatis-config-reasonable.xml ================================================ ================================================ FILE: src/test/resources/xugu/mybatis-config-rowbounds.xml ================================================ ================================================ FILE: src/test/resources/xugu/mybatis-config.xml ================================================ ================================================ FILE: src/test/resources/xugu/mysql.sql ================================================ CREATE DATABASE pagehelper CHARACTER SET utf8; USE pagehelper; DROP TABLE IF EXISTS `user`; CREATE TABLE `user` ( `id` int IDENTITY(1,1) NOT NULL, `name` varchar(50) DEFAULT NULL, `py` varchar(50) DEFAULT NULL, PRIMARY KEY (`Id`) ) ; insert into `user`(id, name, py) values('1','毕淑儒','BSR'); insert into `user`(id, name, py) values('2','蔡兴熙','CXX'); insert into `user`(id, name, py) values('3','曾三杰','ZSJ'); insert into `user`(id, name, py) values('4','常元琴','CYQ'); insert into `user`(id, name, py) values('5','陈栋芬','CDF'); insert into `user`(id, name, py) values('6','陈宁婷','CNZ'); insert into `user`(id, name, py) values('7','陈瑞','CR'); insert into `user`(id, name, py) values('8','陈武宵','CWX'); insert into `user`(id, name, py) values('9','陈晓丽','CXL'); insert into `user`(id, name, py) values('10','陈翼涛','CYT'); insert into `user`(id, name, py) values('11','陈宇然','CYR'); insert into `user`(id, name, py) values('12','陈震','CZ'); insert into `user`(id, name, py) values('13','程太君','CTJ'); insert into `user`(id, name, py) values('14','程玉娜','CYN'); insert into `user`(id, name, py) values('15','丛贺轩','CHX'); insert into `user`(id, name, py) values('16','戴国宇','DGY'); insert into `user`(id, name, py) values('17','戴杰亮','DJL'); insert into `user`(id, name, py) values('18','丁玉华','DYH'); insert into `user`(id, name, py) values('19','董秋明','DQM'); insert into `user`(id, name, py) values('20','董政厚','DZH'); insert into `user`(id, name, py) values('21','杜玉焱','DYZ'); insert into `user`(id, name, py) values('22','段瑜芝','DZZ'); insert into `user`(id, name, py) values('23','傅广友','FGY'); insert into `user`(id, name, py) values('24','傅井飞','FJF'); insert into `user`(id, name, py) values('25','高辉涛','GHT'); insert into `user`(id, name, py) values('26','高龙飞','GLF'); insert into `user`(id, name, py) values('27','高汝英','GRY'); insert into `user`(id, name, py) values('28','高云天','GYT'); insert into `user`(id, name, py) values('29','郭义民','GYM'); insert into `user`(id, name, py) values('30','郭永洪','GYH'); insert into `user`(id, name, py) values('31','韩国茜','HGZ'); insert into `user`(id, name, py) values('32','韩龙康','HLK'); insert into `user`(id, name, py) values('33','韩伟佳','HWJ'); insert into `user`(id, name, py) values('34','韩扬谦','HYQ'); insert into `user`(id, name, py) values('35','郝静生','HJS'); insert into `user`(id, name, py) values('36','何柏红','HBH'); insert into `user`(id, name, py) values('37','何彩智','HCZ'); insert into `user`(id, name, py) values('38','何陶增','HTZ'); insert into `user`(id, name, py) values('39','何薇','HZ'); insert into `user`(id, name, py) values('40','何小凡','HXF'); insert into `user`(id, name, py) values('41','何振平','HZP'); insert into `user`(id, name, py) values('42','洪彩辉','HCH'); insert into `user`(id, name, py) values('43','胡仕明','HSM'); insert into `user`(id, name, py) values('44','黄建朋','HJP'); insert into `user`(id, name, py) values('45','黄祥荣','HXR'); insert into `user`(id, name, py) values('46','黄璇平','HZP'); insert into `user`(id, name, py) values('47','贾茂飞','JMF'); insert into `user`(id, name, py) values('48','李迪茹','LDR'); insert into `user`(id, name, py) values('49','李桂博','LGB'); insert into `user`(id, name, py) values('50','李国祯','LGZ'); insert into `user`(id, name, py) values('51','李宏川','LHC'); insert into `user`(id, name, py) values('52','李梅','LM'); insert into `user`(id, name, py) values('53','李媚文','LMW'); insert into `user`(id, name, py) values('54','李孟惠','LMH'); insert into `user`(id, name, py) values('55','李南懋','LNZ'); insert into `user`(id, name, py) values('56','李鹏龙','LPL'); insert into `user`(id, name, py) values('57','李诗庸','LSY'); insert into `user`(id, name, py) values('58','李姝勇','LZY'); insert into `user`(id, name, py) values('59','李树鹏','LSP'); insert into `user`(id, name, py) values('60','李薇红','LZH'); insert into `user`(id, name, py) values('61','李文章','LWZ'); insert into `user`(id, name, py) values('62','李星佳','LXJ'); insert into `user`(id, name, py) values('63','李兴','LX'); insert into `user`(id, name, py) values('64','李秀倩','LXZ'); insert into `user`(id, name, py) values('65','李艳生','LYS'); insert into `user`(id, name, py) values('66','李燕金','LYJ'); insert into `user`(id, name, py) values('67','李玉彪','LYB'); insert into `user`(id, name, py) values('68','李振峰','LZF'); insert into `user`(id, name, py) values('69','梁斌芳','LBF'); insert into `user`(id, name, py) values('70','梁国云','LGY'); insert into `user`(id, name, py) values('71','梁巧爱','LQA'); insert into `user`(id, name, py) values('72','梁照金','LZJ'); insert into `user`(id, name, py) values('73','林婧美','LZM'); insert into `user`(id, name, py) values('74','林沛寿','LPS'); insert into `user`(id, name, py) values('75','林薇程','LZC'); insert into `user`(id, name, py) values('76','林伟玉','LWY'); insert into `user`(id, name, py) values('77','林艺玲','LYL'); insert into `user`(id, name, py) values('78','刘睿','LR'); insert into `user`(id, name, py) values('79','刘芊芊','LQQ'); insert into `user`(id, name, py) values('80','刘海波','LHB'); insert into `user`(id, name, py) values('81','刘斓琴','LZQ'); insert into `user`(id, name, py) values('82','刘磊东','LLD'); insert into `user`(id, name, py) values('83','刘明琪','LMZ'); insert into `user`(id, name, py) values('84','刘铭恩','LME'); insert into `user`(id, name, py) values('85','刘任恺','LRZ'); insert into `user`(id, name, py) values('86','刘水秋','LSQ'); insert into `user`(id, name, py) values('87','刘文萱','LWZ'); insert into `user`(id, name, py) values('88','刘祥瑶','LXY'); insert into `user`(id, name, py) values('89','刘薪坪','LXP'); insert into `user`(id, name, py) values('90','刘秀涛','LXT'); insert into `user`(id, name, py) values('91','刘彦利','LYL'); insert into `user`(id, name, py) values('92','刘益存','LYC'); insert into `user`(id, name, py) values('93','龙子苹','LZP'); insert into `user`(id, name, py) values('94','卢秀剑','LXJ'); insert into `user`(id, name, py) values('95','罗乔华','LQH'); insert into `user`(id, name, py) values('96','罗希清','LXQ'); insert into `user`(id, name, py) values('97','马家兰','MJL'); insert into `user`(id, name, py) values('98','马莲莹','MLY'); insert into `user`(id, name, py) values('99','马宁文','MNW'); insert into `user`(id, name, py) values('100','马水鹏','MSP'); insert into `user`(id, name, py) values('101','孟三云','MSY'); insert into `user`(id, name, py) values('102','孟寿云','MSY'); insert into `user`(id, name, py) values('103','聂伟元','NWY'); insert into `user`(id, name, py) values('104','潘永飞','PYF'); insert into `user`(id, name, py) values('105','彭健颖','PJY'); insert into `user`(id, name, py) values('106','钱文松','QWS'); insert into `user`(id, name, py) values('107','屈江珍','QJZ'); insert into `user`(id, name, py) values('108','邵建林','SJL'); insert into `user`(id, name, py) values('109','施家晖','SJZ'); insert into `user`(id, name, py) values('110','施艺英','SYY'); insert into `user`(id, name, py) values('111','孙常程','SCC'); insert into `user`(id, name, py) values('112','谭佳盈','TJY'); insert into `user`(id, name, py) values('113','唐春珊','TCS'); insert into `user`(id, name, py) values('114','唐军霞','TJX'); insert into `user`(id, name, py) values('115','唐里丽','TLL'); insert into `user`(id, name, py) values('116','陶姐华','TJH'); insert into `user`(id, name, py) values('117','万圻艳','WZY'); insert into `user`(id, name, py) values('118','王傲凤','WAF'); insert into `user`(id, name, py) values('119','王德英','WDY'); insert into `user`(id, name, py) values('120','王鼎华','WDH'); insert into `user`(id, name, py) values('121','王慧','WH'); insert into `user`(id, name, py) values('122','王佳光','WJG'); insert into `user`(id, name, py) values('123','王家胜','WJS'); insert into `user`(id, name, py) values('124','王竞飞','WJF'); insert into `user`(id, name, py) values('125','王科磊','WKL'); insert into `user`(id, name, py) values('126','王丽章','WLZ'); insert into `user`(id, name, py) values('127','王励苗','WLM'); insert into `user`(id, name, py) values('128','王美东','WMD'); insert into `user`(id, name, py) values('129','王美媛','WMZ'); insert into `user`(id, name, py) values('130','王蕊颖','WRY'); insert into `user`(id, name, py) values('131','王士成','WSC'); insert into `user`(id, name, py) values('132','王熙斌','WXB'); insert into `user`(id, name, py) values('133','王香军','WXJ'); insert into `user`(id, name, py) values('134','王休娜','WXN'); insert into `user`(id, name, py) values('135','王仪行','WYX'); insert into `user`(id, name, py) values('136','王赢基','WYJ'); insert into `user`(id, name, py) values('137','王云芯','WYX'); insert into `user`(id, name, py) values('138','王郑林','WZL'); insert into `user`(id, name, py) values('139','王治良','WZL'); insert into `user`(id, name, py) values('140','王忠宇','WZY'); insert into `user`(id, name, py) values('141','王子冰','WZB'); insert into `user`(id, name, py) values('142','韦新裕','WXY'); insert into `user`(id, name, py) values('143','魏复冉','WFR'); insert into `user`(id, name, py) values('144','吴翰志','WHZ'); insert into `user`(id, name, py) values('145','吴美森','WMS'); insert into `user`(id, name, py) values('146','吴翔良','WXL'); insert into `user`(id, name, py) values('147','吴艳伟','WYW'); insert into `user`(id, name, py) values('148','吴钲辉','WZH'); insert into `user`(id, name, py) values('149','向盼洛','XPL'); insert into `user`(id, name, py) values('150','萧恩','XE'); insert into `user`(id, name, py) values('151','萧军杰','XJJ'); insert into `user`(id, name, py) values('152','萧圣梅','XSM'); insert into `user`(id, name, py) values('153','谢辰吉','XCJ'); insert into `user`(id, name, py) values('154','徐郎求','XLQ'); insert into `user`(id, name, py) values('155','徐铭森','XMS'); insert into `user`(id, name, py) values('156','徐蓉伟','XRW'); insert into `user`(id, name, py) values('157','许为梧','XWW'); insert into `user`(id, name, py) values('158','阎皓河','YZH'); insert into `user`(id, name, py) values('159','阎思华','YSH'); insert into `user`(id, name, py) values('160','杨爱秀','YAX'); insert into `user`(id, name, py) values('161','杨昆飞','YKF'); insert into `user`(id, name, py) values('162','杨良林','YLL'); insert into `user`(id, name, py) values('163','杨少君','YSJ'); insert into `user`(id, name, py) values('164','杨玉丽','YYL'); insert into `user`(id, name, py) values('165','杨之安','YZA'); insert into `user`(id, name, py) values('166','尤榕锋','YZF'); insert into `user`(id, name, py) values('167','余俊珠','YJZ'); insert into `user`(id, name, py) values('168','袁江蔓','YJM'); insert into `user`(id, name, py) values('169','张必翰','ZBH'); insert into `user`(id, name, py) values('170','张昌颜','ZCY'); insert into `user`(id, name, py) values('171','张恩星','ZEX'); insert into `user`(id, name, py) values('172','张飞强','ZFQ'); insert into `user`(id, name, py) values('173','张凤焯','ZFZ'); insert into `user`(id, name, py) values('174','张国强','ZGQ'); insert into `user`(id, name, py) values('175','张计欣','ZJX'); insert into `user`(id, name, py) values('176','张家颖','ZJY'); insert into `user`(id, name, py) values('177','张金安','ZJA'); insert into `user`(id, name, py) values('178','张莉','ZL'); insert into `user`(id, name, py) values('179','张米龙','ZML'); insert into `user`(id, name, py) values('180','张善渊','ZSY'); insert into `user`(id, name, py) values('181','张万敏','ZWM'); insert into `user`(id, name, py) values('182','张晓林','ZXL'); insert into `user`(id, name, py) values('183','张秀高','ZXG'); ================================================ FILE: wikis/en/Changelog.md ================================================ ## Changelog ### 6.1.1 - 2025-06-20 - Add pagination support for SunDB database **by wangsl** - Add adapter support for Xugu (虚谷数据库) database **by 吴启洋** - Fix issue where `additionalParameter` was not properly copied when copying `countBoundSql` **by yefeng** - Fix `offsetPage` example code error **by S00ahKim** - Fix Jakarta/Javax ServletRequest compatibility issue, support Spring Boot 3.x **by PING** - Add `PageInfo.of()` overloaded method to support manually specifying total record count for pagination info **by yesAnd** - Upgrade MyBatis version to 3.5.19 (from 3.5.10) - Upgrade Guava version to 33.4.8-jre (from 32.0.0-jre) - Upgrade Logback Classic version to 1.2.13 (from 1.2.11) - Optimize Xugu JDBC dependency configuration, add `test` - Fix typos and link references in English documentation **by Coco Liliace** - Add relevant comments to improve code readability **by yesAnd** - Resolve dependency security vulnerabilities, update related component versions #### Compatibility Notes - This version maintains backward compatibility with previous versions - New database support: SunDB, Xugu (虚谷数据库) - Fixed Spring Boot 3.x compatibility issues, recommended for users using Jakarta EE #### Upgrade Recommendations - All users are recommended to upgrade, especially those using Spring Boot 3.x or requiring new database support - Users of SunDB or Xugu databases can directly use pagination features - Please ensure dependency version compatibility before ### 6.1.0 - 2023-12-16 - Released version 6.1.0, PageHelper provides direct dependency on jsqlparser as intermediate interfaces, allowing default implementation replacement through SPI. - Upgraded jsqlparser version to 4.7, re-implemented order by, pagination, and count queries. - Simplified pom.xml configuration, removed shade-embedded jsqlparser approach, and switched to selecting different jsqlparser versions through external dependencies, allowing self-SPI extension. - jsqlparser parsing no longer uses a thread pool, supporting SPI extension to override SqlParser implementation. - Changed SqlServer pagination to SqlServerSqlParser interface, added parameter sqlServerSqlParser to override the default value. - Extracted OrderByParser to OrderBySqlParser interface, added orderBySqlParser parameter to override the default implementation. - Changed static methods of OrderByParser to regular methods, preparing for future interface changes. - JSqlParser interface is no longer needed after JDK 8+, removed the interface, and marked the parameter in the documentation (_This parameter was used in the early stages to support special configuration for SQL Server_). Compatible with jsqlparser 4.7 version. - Fixed maven-compiler-plugin version to remove warnings and improve build stability. qxo - Added .vscode to .gitignore for vscode IDE. qxo - Fixed bug https://github.com/pagehelper/Mybatis-PageHelper/issues/779. chenyuehui To ensure compatibility with jsqlparser 4.5, 4.7, and possible future versions, a new project called pagehelper-sqlparser has been created. Currently, it provides two implementations: 4.5 and 4.7. To use it, exclude jsqlparser from pagehelper and select one jsqlparser implementation. The current version defaults to using the code from version 4.7. If you want to switch to the 4.5 implementation, follow the configuration steps below: ```xml com.github.pagehelper pagehelper 6.1.0 com.github.jsqlparser jsqlparser com.github.pagehelper sqlparser4.5 6.1.0 ``` The priority of replacing default values with SPI is lower than the implementations specified by the sqlServerSqlParser, orderBySqlParser, and countSqlParser parameters. If no specific implementation is specified, the SPI implementation will take effect if available. You can refer to the code in the pagehelper-sqlsource module for SPI implementation examples. By default, JSqlParser uses a temporarily created `Executors.newSingleThreadExecutor()` for parsing SQL. Here, the thread pool is bypassed through the API: ```java CCJSqlParser parser = CCJSqlParserUtil.newParser(statementReader); parser.withSquareBracketQuotation(true); return parser.Statement(); ``` The purpose of using a thread pool in JSqlParser is to prevent parsing timeouts. Therefore, if you have encountered timeout situations, you can introduce the following dependency (which overrides the default implementation through SPI with a timeout of 10 seconds): ```xml com.github.pagehelper sqlparser-timeout 6.1.0 ``` ### 6.0.0 - 2023-11-05 - Based on JDK 8 adaptation, JDK 6 and 7 are not supported from 6.0 onwards, and 5.x versions can be used if necessary - Added asynchronous count support, configure `asyncCount` globally, default `false`,single activation by `PageHelper.startPage(1, 10).enableAsyncCount()`; Asynchronous queries are performed using independent connections (transactions), and it is not suitable to enable asynchronous queries when the query is affected by addition, deletion, and modification operations. closed #334 - JSqlParser opens `parser.withSquareBracketQuotation(true)` by default and supports SqlServer `[]`(**6.1.0 remove this parameter**) - feat: A new method for data object conversion has been added to the `PageInfo`, method: ` PageInfo convert(Page.Function function)` **by codeke** - `CountSqlParser` is changed to an interface, allowing the `countSqlParser` parameter to be replaced with your own implementation, which is supported #772 - `dialectAlias` supports simplified configurations, e.g. `dm=oracle;oracle=oracle9i`, a direct reference to the current abbreviation, without writing the full name of the class - `countColumn`add injection detection, fixed #686 - Add the `PageParam` class, which does not embed objects (will affect the use), if you want to use, you can inherit the object,closed #562 - All exception messages have been changed to English - open `setLocalPage` method, support #771 - Solve the problem of handling order by error when `sqlserver` with union sql parsing,fixed #768 - Optimized the total logic to solve the problem that the query is not pagination and the order by is invalid. fixed #641 - Modify the dialect instantiation logic to ensure that the class is used after the configuration is completed. fixed #742 - `dialectAliasMap` change to `LinkedHashMap` type, support matching in configuration order, fixed #758 - fixed the pagination bug of xingyun database **by maimaitiyaer_bonc** - ### 5.3.3 - 2023-06-03 - Ignoring unnecessarily generated surefire-report **by java-codehunger** - Supports parsing of the dialect corresponding to the openGauss database from the URL **by saxisuer** - Fixed the issue that SQL injection verification was incorrect #716 **by uyong** - Support parsing of the dialect corresponding to Kingbase 8 from the URL **by univ** - Add support for cirrodata #705 **by sxh0570** ### 5.3.2 - 2022-09-18 - Use document update, all parameters are included, the default home page document changed to Chinese. - Add support for kingbase. by **HanHuimin001** - Add 'debug' parameter, default 'false', turn on 'debug' mode when 'true', call stack will be recorded after 'debug' mode starts. by **huyingqian** - add supports for count sql hint syntax. by **zhanliquan** - Add a `PageProperties` interface, which can be used by the instantiated extension class inside the framework to obtain the paging plug-in configuration. - To add the `CountMsIdGen` interface, you can configure a custom implementation class by `CountMsIdGen`, which is used to generate the msId for the query corresponding to the COUNT query. The default implementation is still `countSuffix` , with extensions like 'selectByExample' mapped to the corresponding 'selectCountByExample' method. - Added `keepOrderBy` and `keepSubSelectOrderBy` configurations. - Add the `sqlParser` configuration and add the `JSqlParser` interface to solve the problem that JSqlParser and JDK compatibility cause no additional configuration.(**6.1.0 remove this parameter**) - The test uses the Logback logging framework and removes log4j. - Resolve that 'dialectKey' is empty resulting in NPE,fixed #656 For a detailed description of the above parameters, see [**How to use PageHelper**](HowToUse.md). ### 5.3.1 - 2022-06-14 - Resolve CVE-2022-28111 vulnerability, limit the order by parameter, avoid SQL injection - Add support for as400. **by bluezealot** - Optimize generic parameters of `Page` class **by Zhang Fulai * * - Standardize the order of PostgreSQL paging parameters **by outian** ### 5.3.0 - 2021-10-07 - Add `AutoDialect` interface to automatically obtain the database type, which can be configured as its own implementation class through `autoDialectClass`. By default, `DataSourceNegotiationAutoDialect` is used, which is obtained according to the connection pool first. In the default implementation, special processing is added for `hikari,druid,tomcat-jdbc,c3p0,dbcp` type database connection pools, and jdbcUrl are obtained directly from the configuration. When other types of data sources are used, the connection is still obtained in the old way. You can configure `autoDialectClass=old` when you want to use exactly the same way as the old version. When the database connection pool type is very clear, it is recommended to configure it as a specific value. For example, when using hikari, configure `autoDialectClass=hikari`, and when using other connection pools, configure it as its own implementation class. - Enable dynamic designation of dialect implementation at runtime, such as `PageHelper.startPage(1, 10).using("oracle");` Or `PageHelper.startPage(2, 10).using("org.exmaple.CustomDialect");` - `PageInfo` adds the empty instance constant attribute `PageInfo.EMPTY` and the content judgment `boolean hasContent()` . - Adding banner to startup requires log level debug, which can be closed by `-Dpagehelper.banner=false` or environment variable `PAGEHELPER_BANNER=false`. ``` DEBUG [main] - ,------. ,--. ,--. ,--. | .--. ' ,--,--. ,---. ,---. | '--' | ,---. | | ,---. ,---. ,--.--. | '--' | ' ,-. | | .-. | | .-. : | .--. | | .-. : | | | .-. | | .-. : | .--' | | --' \ '-' | ' '-' ' \ --. | | | | \ --. | | | '-' ' \ --. | | `--' `--`--' .`- / `----' `--' `--' `----' `--' | |-' `----' `--' `---' `--' is intercepting. ``` The purpose of adding banner is that if you configure paging plug-ins multiple times, you will see banner output multiple times, and you can see where it has been instantiated at the breakpoint of the `PageInterceptor` constructor. - Improve the Count query. When having exists, the query column is not optimized. The query column is not optimized when there are functions or operations with aliases in the column, so as to avoid that aliases used in order by or having do not exist. - It is judged that processing some data (such as TDEngine) returns null when there is no result in querying count. - Adding Firebird database support is the same as SqlServer2012 paging syntax. - Add impala database automatic recognition. - Upgrade JSqlParser to version 4.2. ### 5.2.1 - 2021-06-20 - Upgrade dependency jsqlparser 4.0, mybatis 3.5.7 - Automatically recognize the following databases: - 虚谷数据库 xugu #599 - 神通数据库 oscar by **ranqing** - 瀚高数据库 highgo by **ashaiqing** - BoundSqlInterceptorChain interceptor index parameter bug, fixed #587 - fixed #558 - Add PostgreSQL dialect by **liym@home** - fixed #604, Solve the problem of total loss - Add code comments, fixed #547 ### 5.2.0 - 2020-07-26 - Upgrading jsqlparser to version 3.2 makes sql parsing better and supports sqlserver better. - Modify the substitution regularity in sqlserver mode, and now allow spaces in `with( nolock)` brackets. - Solving the bugs in reasonable, pageSizeZero and offset usage, the meaning and result are more consistent now. - In the process of splicing paging SQL, a new line character is added to avoid invalid paging part caused by comments in the original SQL. - ROW_ID alias in Oracle and Db2 is changed to PAGEHELPER_ROW_ID to avoid conflict with common names. - Solve the special problem when using other interceptors with a single parameter ProviderSql (support mybatis 3.4.0+) [by Luo Zhenyu](https://github.com/luozhenyu) - Automatic identification of clickhouse is supported, and paging is performed by MySQL. - Change startRow, endRow type from int to long. - Page adds a `public PageInfo toPageInfo(Function function)` method to convert the data in the query results. - Refer to `Oracle9iDialect` provided by pr#476, which is also a paging method used before. You can test and select the appropriate paging method by yourself. At present, there are two kinds of Oracle pagination as follows: ```sql -- OracleDialect outer control range WHERE ROW_ID <= ? AND ROW_ID > ? -- Oracle9iDialect's internal and external control scope respectively TMP_PAGE WHERE ROWNUM <= ? ) WHERE ROW_ID > ? ``` - Adding `BoundSqlInterceptor` of PageHelper plug-in can process or simply read SQL in three stages, adding `boundSqlInterceptors`, and configuring multiple implementation class names that implement `BoundSqlInterceptor` interface, separated by English commas. PageHelper can also be set for this paging through a `PageHelper.startPage(x,x).boundSqlInterceptor(BoundSqlInterceptor boundSqlInterceptor)`. The biggest change of this update is the addition of `BoundSqlInterceptor`, which can intercept the SQL(BoundSQL object) of paging processing at runtime: ```java /** * BoundSql 处理器 */ public interface BoundSqlInterceptor { /** * boundsql 处理 * * @param type 类型 * @param boundSql 当前类型的 boundSql * @param cacheKey 缓存 key * @param chain 处理器链,通过 chain.doBoundSql 方法继续执行后续方法,也可以直接返回 boundSql 终止后续方法的执行 * @return 允许修改 boundSql 并返回修改后的 */ BoundSql boundSql(Type type, BoundSql boundSql, CacheKey cacheKey, Chain chain); enum Type { /** * 原始SQL,分页插件执行前,先执行这个类型 */ ORIGINAL, /** * count SQL,第二个执行这里 */ COUNT_SQL, /** * 分页 SQL,最后执行这里 */ PAGE_SQL } /** * 处理器链,可以控制是否继续执行 */ interface Chain { Chain DO_NOTHING = new Chain() { @Override public BoundSql doBoundSql(Type type, BoundSql boundSql, CacheKey cacheKey) { return boundSql; } }; BoundSql doBoundSql(Type type, BoundSql boundSql, CacheKey cacheKey); } } ``` The interface includes boundSql interface method, Type enumeration, and the definition of Chain interface, and you don't need to consider Chain when you implement it yourself. The interceptor is configured by `boundSqlInterceptors` parameter, and there are three situations when executing: 1. Regardless of whether the currently executed SQL will be paged or not, interceptor methods of `Type.ORIGINAL` will be executed. 2. When the paging method is called, the interceptor will continue to execute the interceptor method of `Type.COUNT_SQL`, which will only be executed when paging is executed and count query is specified. 3. When paging method is called, if count > 0, interceptor method of `Type.PAGE_SQL` will be executed, which will only be executed when paging is executed. >With the specified parameter `PageHelper.startPage(1, Integer.MAX_VALUE, false).boundSqlInterceptor(BoundSqlInterceptor boundSqlInterceptor)`, it can also play the role of not paging and count query, but can execute interceptor method of `Type.ORIGINAL`. If you want to get the page before SQL execution, you only need to pay attention to `Type.ORIGINAL`, and the other two are before count execution and before page execution (when count=0, the page method will not be executed and will not be executed here). Take the test code as an example: ```java public class TestBoundSqlInterceptor implements BoundSqlInterceptor { public static final String COMMENT = "\n /* TestBoundSqlInterceptor */\n"; @Override public BoundSql boundSql(Type type, BoundSql boundSql, CacheKey cacheKey, Chain chain) { if (type == Type.ORIGINAL) { String sql = boundSql.getSql(); MetaObject metaObject = MetaObjectUtil.forObject(boundSql); metaObject.setValue("sql", sql + COMMENT); } return chain.doBoundSql(type, boundSql, cacheKey); } } ``` The above code modifies the original sql before SQL execution, but only adds a comment at the end, which does not affect SQL execution. It is configured in the following way: ```xml ``` Here, in order to explain that the parameter value can be multiple, it is repeatedly configured once, that is, the above interceptor will execute it twice. With this configuration, the above SQL will modify the SQL when the page is executed. In addition to this configuration mode, temporary designation when PageHelper.startPage is also supported. This mode will put the interceptor at the chain head and execute it first, so you can control whether to execute it later or not, or you can do the final processing before returning after all subsequent executions. Example: ```java PageHelper.startPage(1, 10).boundSqlInterceptor(new BoundSqlInterceptor() { @Override public BoundSql boundSql(Type type, BoundSql boundSql, CacheKey cacheKey, Chain chain) { System.out.println("before: " + boundSql.getSql()); BoundSql doBoundSql = chain.doBoundSql(type, boundSql, cacheKey); System.out.println("after: " + doBoundSql.getSql()); if (type == Type.ORIGINAL) { Assert.assertTrue(doBoundSql.getSql().contains(TestBoundSqlInterceptor.COMMENT)); } return doBoundSql; } }); ``` ### 5.1.11 - 2019-11-26 - Added support for Shentong database **wangss** - Add support for HerdDB - support HerdDB, mostly like MySQL - auto detect HerdDB **Enrico Olivelli** - fix some typos and grammar issues **LHearen** ### 5.1.10 - 2019-06-05 In version *5.1.0 - 2017-08-28*. Added `ReplaceSql` interface for handling sqlServer with (nolock) problem, add the replaceSql parameters, the optional value is `simple` and `regex`, or to achieve the `ReplaceSql` interface fully qualified class name. The default value is `simple`, still using the original way to deal with, the new regex will be convert `with (nolock)` to `table_PAGEWITHNOLOCK`. This update only changes the default value from `simple` to `regex`, which can almost 100% solve the paging problem of sqlServer. The following are examples from two issue. #### issue [#76](https://github.com/pagehelper/pagehelper-spring-boot/issues/76) Original SQL: ```sql SELECT * FROM forum_post_info a with(nolock) LEFT JOIN forum_carcase_tags as b with(nolock) on a.id = b.carcase_id where b.tag_id = 127 ``` Converted Count SQL: ```sql SELECT COUNT(0) FROM forum_post_info a WITH (NOLOCK) LEFT JOIN forum_carcase_tags b WITH (NOLOCK) ON a.id = b.carcase_id WHERE b.tag_id = 127 ``` Converted paging SQL: ```sql SELECT TOP 10 * FROM ( SELECT ROW_NUMBER() OVER (ORDER BY RAND()) AS PAGE_ROW_NUMBER, * FROM ( SELECT * FROM forum_post_info a WITH (NOLOCK) LEFT JOIN forum_carcase_tags b WITH (NOLOCK) ON a.id = b.carcase_id WHERE b.tag_id = 127 ) PAGE_TABLE_ALIAS ) PAGE_TABLE_ALIAS WHERE PAGE_ROW_NUMBER > 1 ORDER BY PAGE_ROW_NUMBER ``` #### issue [#398](https://github.com/pagehelper/Mybatis-PageHelper/issues/398) Original SQL: ```sql Select AUS.ScheduleID, AUS.SystemID, AUS.ClinicID, AUS.DoctorID, AUS.ScheduleDate, AUS.StartTime, AUS.EndTime, AUS.Status, AUS.BookBy, AUS.Note, AUS.Remark, AUS.SourceType, CM.CompanyName, AU.UserName As DoctorName, AU.UserNumber As DoctorNumber, CC.CodeDesc As ClinicName, CD.Lat, CD.Lng, CD.ContactTel, CD.Address, CR.ConsultationStatusID, CR.RegisterStatus,A1.CodeDesc as AreaLevel1, A2.CodeDesc as AreaLevel2 From ACM_User_Schedule AUS with(nolock) Left Join Client_Register CR with(nolock) On AUS.BookBy=CR.ClientID And CR.SourceType='F' And AUS.ClientRegisterNum=CR.ClientRegisterNum Inner Join ACM_User AU with(nolock) On AU.UserID = AUS.DoctorID Inner Join Code_Clinic CC with(nolock) On AUS.ClinicID=CC.CodeID Inner Join Clinic_Detail CD with(nolock) On CC.CodeID = CD.ClinicID Inner Join Code_Area A1 with(nolock) On CD.AreaLevel1ID=A1.CodeID Inner Join Code_Area A2 with(nolock) On CD.AreaLevel2ID=A2.CodeID Inner Join Company_Master CM with(nolock) On CC.SystemID = CM.SystemID Where BookBy=1 ``` Converted Count SQL: ```sql SELECT COUNT(0) FROM ACM_User_Schedule AUS WITH (NOLOCK) LEFT JOIN Client_Register CR WITH (NOLOCK) ON AUS.BookBy = CR.ClientID AND CR.SourceType = 'F' AND AUS.ClientRegisterNum = CR.ClientRegisterNum INNER JOIN ACM_User AU WITH (NOLOCK) ON AU.UserID = AUS.DoctorID INNER JOIN Code_Clinic CC WITH (NOLOCK) ON AUS.ClinicID = CC.CodeID INNER JOIN Clinic_Detail CD WITH (NOLOCK) ON CC.CodeID = CD.ClinicID INNER JOIN Code_Area A1 WITH (NOLOCK) ON CD.AreaLevel1ID = A1.CodeID INNER JOIN Code_Area A2 WITH (NOLOCK) ON CD.AreaLevel2ID = A2.CodeID INNER JOIN Company_Master CM WITH (NOLOCK) ON CC.SystemID = CM.SystemID WHERE BookBy = 1 ``` Converted paging SQL: ```sql SELECT TOP 10 ScheduleID, SystemID, ClinicID, DoctorID, ScheduleDate , StartTime, EndTime, Status, BookBy, Note , Remark, SourceType, CompanyName, DoctorName, DoctorNumber , ClinicName, Lat, Lng, ContactTel, Address , ConsultationStatusID, RegisterStatus, AreaLevel1, AreaLevel2 FROM ( SELECT ROW_NUMBER() OVER (ORDER BY RAND()) AS PAGE_ROW_NUMBER, ScheduleID, SystemID, ClinicID, DoctorID , ScheduleDate, StartTime, EndTime, Status, BookBy , Note, Remark, SourceType, CompanyName, DoctorName , DoctorNumber, ClinicName, Lat, Lng, ContactTel , Address, ConsultationStatusID, RegisterStatus, AreaLevel1, AreaLevel2 FROM ( SELECT AUS.ScheduleID, AUS.SystemID, AUS.ClinicID, AUS.DoctorID, AUS.ScheduleDate , AUS.StartTime, AUS.EndTime, AUS.Status, AUS.BookBy, AUS.Note , AUS.Remark, AUS.SourceType, CM.CompanyName, AU.UserName AS DoctorName, AU.UserNumber AS DoctorNumber , CC.CodeDesc AS ClinicName, CD.Lat, CD.Lng, CD.ContactTel, CD.Address , CR.ConsultationStatusID, CR.RegisterStatus, A1.CodeDesc AS AreaLevel1, A2.CodeDesc AS AreaLevel2 FROM ACM_User_Schedule AUS WITH (NOLOCK) LEFT JOIN Client_Register CR WITH (NOLOCK) ON AUS.BookBy = CR.ClientID AND CR.SourceType = 'F' AND AUS.ClientRegisterNum = CR.ClientRegisterNum INNER JOIN ACM_User AU WITH (NOLOCK) ON AU.UserID = AUS.DoctorID INNER JOIN Code_Clinic CC WITH (NOLOCK) ON AUS.ClinicID = CC.CodeID INNER JOIN Clinic_Detail CD WITH (NOLOCK) ON CC.CodeID = CD.ClinicID INNER JOIN Code_Area A1 WITH (NOLOCK) ON CD.AreaLevel1ID = A1.CodeID INNER JOIN Code_Area A2 WITH (NOLOCK) ON CD.AreaLevel2ID = A2.CodeID INNER JOIN Company_Master CM WITH (NOLOCK) ON CC.SystemID = CM.SystemID WHERE BookBy = 1 ) PAGE_TABLE_ALIAS ) PAGE_TABLE_ALIAS WHERE PAGE_ROW_NUMBER > 1 ORDER BY PAGE_ROW_NUMBER ``` SQL is formatted by https://tool.oschina.net/codeformat/sql ### 5.1.9 - 2019-05-29 - Upgrade jsqlparser to 2.0, upgrade mybatis to 3.5.1. resolve compatibility issues. - Improve paging logic judgment. fixed #389 - Solve MetaObject version compatibility issues. fixed #349 - Processing order by output warning log when parsing fails, not throwing exception - Solve three problems that may cause countColumn to fail fixed #325 - Add a comma with less BIT_ fixed #341 - Handling invalid links in documents isea533 - Document sample error. fixed #366 - fixed #373 NPE problem ### 5.1.8 - 2018-11-11 - Resolve the problem of `with(nolock)` in SQLServer ([#pr10](https://gitee.com/free/Mybatis_PageHelper/pulls/10)) by [lvshuyan](https://gitee.com/lvshuyan) ### 5.1.7 - 2018-10-11 - Support Aliyun PPAS database. Automatic identification of edb. fixed #281 ### 5.1.6 - 2018-09-05 - Add the parameter useSqlserver2012, set to true, and use sqlserver2012(Dialect) as the default paging method for SQL Server databases, which is useful in dynamic data sources. - Add an IPage interface. Currently, there is only one parameter to support the MyBatis query method, and when the parameter implements the IPage interface, paging query will be automatically performed if paging parameters exist. Thanks to [moonfruit](https://github.com/moonfruit) Issue two years ago. - fixed # 276 to resolve hashset concurrency issue - Optimize code structure and streamline interceptor code ### 5.1.5 - 2018-09-02 - Optimize the code and remove unnecessary checks(**by lenosp**) - Solve the small problem of pageKey multi-processing once #268 - Added javadoc documentation on gitee(https://apidoc.gitee.com/free/Mybatis_PageHelper) - Solve the problem of default reflection without cache fixed #275 - Optimizing mysql ifnull function causes paging performance problems (**by miaogr**)(This change was eventually changed to the following `aggregateFunctions`) - Jsqlparser has been upgraded to version 1.2, which is incompatible with 1.0 and has been resolved. fixed 273 - Remove the g(s)etFirstPage and g(s)etLastPage methods that are ambiguous in PageInfo - Throws an exception that failed to parse when sorting fixed #257 - Resolve the initialization problem when there is no properties property when configuring the spring use ``. fixed #26 - Fix the problem that Oracle paging will leak data (**by muyun12**) - `aggregateFunctions`: The default is the aggregate function of all common databases, allowing you to manually add aggregate functions ( affecting the number of rows ). All functions that start with aggregate functions will be wrap as subquery. Other functions and columns will be replaced with count(0). After adding the `aggregateFunctions` parameter, the biggest difference from the original is that if there is `select ifnull(XXX,YY) from table ...`, the original count query is `select count(0) from (select ifnull(xxx,yy) from table ... ) temp_count` now distinguishes aggregate functions, if not aggregate functions, it will become `select count(0) from table ...`. The aggregate function prefixes included by default are as follows: ```java /** * Aggregate functions, beginning with the following functions are considered aggregate functions */ private static final Set AGGREGATE_FUNCTIONS = new HashSet(Arrays.asList( ("APPROX_COUNT_DISTINCT," + "ARRAY_AGG," + "AVG," + "BIT_" + //"BIT_AND," + //"BIT_OR," + //"BIT_XOR," + "BOOL_," + //"BOOL_AND," + //"BOOL_OR," + "CHECKSUM_AGG," + "COLLECT," + "CORR," + //"CORR_," + //"CORRELATION," + "COUNT," + //"COUNT_BIG," + "COVAR," + //"COVAR_POP," + //"COVAR_SAMP," + //"COVARIANCE," + //"COVARIANCE_SAMP," + "CUME_DIST," + "DENSE_RANK," + "EVERY," + "FIRST," + "GROUP," + //"GROUP_CONCAT," + //"GROUP_ID," + //"GROUPING," + //"GROUPING," + //"GROUPING_ID," + "JSON_," + //"JSON_AGG," + //"JSON_ARRAYAGG," + //"JSON_OBJECT_AGG," + //"JSON_OBJECTAGG," + //"JSONB_AGG," + //"JSONB_OBJECT_AGG," + "LAST," + "LISTAGG," + "MAX," + "MEDIAN," + "MIN," + "PERCENT_," + //"PERCENT_RANK," + //"PERCENTILE_CONT," + //"PERCENTILE_DISC," + "RANK," + "REGR_," + "SELECTIVITY," + "STATS_," + //"STATS_BINOMIAL_TEST," + //"STATS_CROSSTAB," + //"STATS_F_TEST," + //"STATS_KS_TEST," + //"STATS_MODE," + //"STATS_MW_TEST," + //"STATS_ONE_WAY_ANOVA," + //"STATS_T_TEST_*," + //"STATS_WSR_TEST," + "STD," + //"STDDEV," + //"STDDEV_POP," + //"STDDEV_SAMP," + //"STDDEV_SAMP," + //"STDEV," + //"STDEVP," + "STRING_AGG," + "SUM," + "SYS_OP_ZONE_ID," + "SYS_XMLAGG," + "VAR," + //"VAR_POP," + //"VAR_SAMP," + //"VARIANCE," + //"VARIANCE_SAMP," + //"VARP," + "XMLAGG").split(","))); ``` ### 5.1.4 - 2018-04-22 - Add the DaMeng Database (dm) to page using Oracle. If you want to change SqlServer, you can refer to the `dialectAlias` parameter in the 5.1.3 update log. ### 5.1.3 - 2018-04-07 - `Page` `toString` method adds `super.toString()`. The final output form is `Page{Attribute}[Collection]`. - New `defaultCount` parameter is used to control whether to perform count query in the default method without count query. By default, `true` will execute count query. This is a globally valid parameter, and it is a uniform behavior when multiple data sources are used. - New `dialogAlias` parameter that allows you to configure aliases for custom implementations. it can be used to automatically obtain corresponding implementations based on JDBC URL. it allows you to overwrite existing implementations in this way. configuration examples are ( Separate multiple configurations with semicolons ): ```xml ``` - The new `PageSerializable` class, a simplified version of the `PageInfo` class, is recommended to use or refer to this class when it does not require much information. ### 5.1.2 - 2017-09-18 - Solve the problem when using the `PageHelper.orderBy` method alone #110; ### 5.1.1 - 2017-08-30 - The update to solve the problem and only SqlServer 2005,2008 related. - Resolve `RegexWithNolockReplaceSql` in the Wrong regular `w?`, it should be `w+`. - Resolved `SqlServerDialect` did not initialize the default `SimpleWithNolockReplaceSql` error. - `SqlServerRowBoundsDialect` support for the replaceSql parameter. ### 5.1.0 - 2017-08-28 - Added the sorting functionality included in the previous version of 4.x, and the usage is consistent (PageHelper adds several sort-related methods). - Paging SQL is converted to PreparedStatement SQL. - Added `ReplaceSql` interface for handling sqlServer with (nolock) problem, add the replaceSql parameters, the optional value is `simple` and `regex`, or to achieve the `ReplaceSql` interface fully qualified class name. The default value is `simple`, still using the original way to deal with, the new regex will be convert `with (nolock)` to `table_PAGEWITHNOLOCK`. - `PageRowBounds` add `count` attribute, you can control whether execute the count query. ### 5.0.4 - 2017-08-01 - Add a simple configuration support for the Phoenix database, You can configure `helperDialect=phoenix`. Can also automatically identify the Phoenix database jdbc url. - Simplified cache of `msCountMap` - Add `countSuffix` count query suffix configuration parameters, this parameter is configured for `PageInterceptor`, the default value is `_COUNT`. - Add custom count query support, see below for details. #### Add custom count query support Add `countSuffix` count query suffix configuration parameters, this parameter is configured for `PageInterceptor`, the default value is `_COUNT`. The paging plugin will preferentially find the handwritten paging query by the current query `msId + countSuffix`. If there is no custom query, the query is still automatically created using the previous way. For example, if there are two queries: ```xml ``` The above `countSuffix` uses the default value of` _COUNT`, and the paging plugin will automatically get the query to `selectLeftjoin_COUNT`. This query needs to ensure that the result is correct. The value of the return value must be `resultType =" Long "`, and the same parameter used by `selectLeftjoin` 'is used, so it is used in SQL to follow the selection of` selectLeftjoin`'. Because the `selectLeftjoin_COUNT` method is invoked automatically, there is no need to provide the appropriate method on the interface, or if it is required to be invoked separately. The above method to perform the portion of the output log is as follows: ``` DEBUG [main] - ==> Preparing: select count(distinct a.id) from user a left join user b on a.id = b.id DEBUG [main] - ==> Parameters: TRACE [main] - <== Columns: C1 TRACE [main] - <== Row: 183 DEBUG [main] - <== Total: 1 DEBUG [main] - Cache Hit Ratio [com.github.pagehelper.mapper.CountryMapper]: 0.0 DEBUG [main] - ==> Preparing: select a.id,b.name,a.py from user a left join user b on a.id = b.id order by a.id LIMIT 10 DEBUG [main] - ==> Parameters: TRACE [main] - <== Columns: ID, COUNTRYNAME, COUNTRYCODE TRACE [main] - <== Row: 1, Angola, AO TRACE [main] - <== Row: 2, Afghanistan, AF TRACE [main] - <== Row: 3, Albania, AL ``` ### 5.0.3 -2017-06-20 - Solve the `supportMethodsArguments` parameter problem. It is recommended to upgrade to the latest version. ### 5.0.2 - 2017-05-30 - `Page` implements `Closeable` interface, in JDK7+ which can use the in `try ()` call, it will automatically call `PageHelper.clearPage ();`[#58](https://github.com/pagehelper/Mybatis-PageHelper/issues/58)。 - fixed: DB2 paging must be specified sub-query alias, or an exception will occur [#52](https://github.com/pagehelper/Mybatis-PageHelper/issues/52) - fixed:if `page.size() == 0` then `pageInfo.isIsLastPage()` is `false` [#50](https://github.com/pagehelper/Mybatis-PageHelper/issues/50) ### 5.0.1 - 2017-04-23 - Add the new parameter `countColumn` used to configure the automatic count column, the default value `0`, that is, `count(0). - The `Page` class is also added with the `countColumn` parameter, which can be configured for a specific query. - Modify the document display problem, by liumian* [PR #30](https://github.com/pagehelper/Mybatis-PageHelper/pull/30) - Resolved sqlserver2012 paging error [42](https://github.com/pagehelper/Mybatis-PageHelper/issues/42) ### 5.0.0 - 2017-01-02 - Use Use [QueryInterceptor spec](https://github.com/pagehelper/Mybatis-PageHelper/blob/master/src/main/java/com/github/pagehelper/QueryInterceptor.java) to handle paging logic - New pagination plugin interceptor `com.github.pagehelper.PageInterceptor` - New `Dialect` `PageHelper` is a special implementation class, the previous function is implemented in more user-friendly ways - New pagination plugin only a `dialect` parameter, the default `dialect` is `PageHelper` - `PageHelper` continue to support previously provided parameters, Among the latest to use the document has been fully updated - `PageHelper` has a `helperDialect` parameter which is the same functional as the previous `dialect` - Added paging implementation based on pure `RowBounds` and `PageRowBounds`, in `com.github. pagehelper. dialect. rowbounds` package, it is used as `dialect` Parameter sample implementation, more detailed documentation will be added later - Removed inappropriate orderby functions that appear in pagination plugin. It will provide a separate sort plug-ins in the future - Remove `PageHelper` are less commonly used methods - A new document, an important part of the update has been mentioned in the changelog, provides the English version of this document - fix bug [#149](http://git.oschina.net/free/Mybatis_PageHelper/issues/149) - renamed Db2RowDialect to Db2RowBoundsDialect - All thrown exceptions being replaced by PageException ## Older Changelogs are written in Chinese You can [view here](https://github.com/pagehelper/Mybatis-PageHelper/blob/master/wikis/zh/Changelog.md) ================================================ FILE: wikis/en/HowToUse.md ================================================ ## HOW TO USE ### 1. Installation #### 1). Using Maven Add the following dependencies to the pom.xml: ```xml com.github.pagehelper pagehelper latestVersion ``` #### 2). Using Gradle To 'build.gradle' add: ```groovy dependencies { compile("com.github.pagehelper:pagehelper:latestVersion") } ``` #### 3). When using Spring Boot Maven: ```xml com.github.pagehelper pagehelper-spring-boot-starter latestVersion ``` Gradle: ```groovy dependencies { compile("com.github.pagehelper:pagehelper-spring-boot-starter:latestVersion") } ``` ### 2. Config PageHelper #### 1). Using in mybatis-config.xml ```xml ``` #### 2). Using in Spring application.xml config `org.mybatis.spring.SqlSessionFactoryBean` as following: ```xml param1=value1 ``` #### 3). Configured in Spring Boot Spring Boot automatically take effect after the introduction of the starter, the paging plug-in configuration, in the Spring the Boot the corresponding configuration file ` application. [properties | yaml] ` configuration: properties: ```properties pagehelper.propertyName=propertyValue pagehelper.reasonable=false pagehelper.defaultCount=true ``` yaml: ```yaml pagehelper: propertyName: propertyValue reasonable: false defaultCount: true # The default parameter of the paging plug-in is in the form of default-count. The parameter of the customized extension must be case - consistent ``` > The default parameter of the paging plug-in is in the form of default-count. The parameter of the customized extension > must be case - consistent. > > Supported default parameters for reference:[PageHelperStandardProperties.java](https://github.com/pagehelper/pagehelper-spring-boot/blob/master/pagehelper-spring-boot-autoconfigure/src/main/java/com/github/pagehelper/autoconfigure/PageHelperStandardProperties.java) #### 4). Banner Setting To avoid errors caused by multiple configurations of the paging plug-in, banner is displayed when the paging plug-in is configured. ``` DEBUG [main] - ,------. ,--. ,--. ,--. | .--. ' ,--,--. ,---. ,---. | '--' | ,---. | | ,---. ,---. ,--.--. | '--' | ' ,-. | | .-. | | .-. : | .--. | | .-. : | | | .-. | | .-. : | .--' | | --' \ '-' | ' '-' ' \ --. | | | | \ --. | | | '-' ' \ --. | | `--' `--`--' .`- / `----' `--' `--' `----' `--' | |-' `----' `--' `---' `--' is intercepting. ``` If the banner is output for many times during the project startup, the paging plug-in has been configured for many times. Check whether the system has configured the paging plug-in based on the log output location. If you don't want to output the banner at startup, you can turn it off via system variables or environment variables. - system variables: `-Dpagehelper.banner=false` - envionment variables: `PAGEHELPER_BANNER=false` #### 5). PageHelper Parameters PageHelper provides several optional parameters, these parameters when used in accordance with the above examples to configuration. **Optional parameters as follows:** 1. `debug` : Debug parameter, default 'false' off, set to 'true' enabled, can check the existence of unsafe calls in the system, [see how to call safely](3-Pagehelper - secure calls). When static methods such as' pageHelper. startPage ' are called to set paging parameters, the current executed method stack information will be recorded. When the query method of MyBatis is executed, the set paging parameters will be used, and the set method stack will be output. If it is not the same as the currently executing method, then the corresponding call in the stack is an unsafe call and needs to be adjusted according to the way in Safe Call (3-PageHelper-Safe Call). An example of the output stack is as follows: ``` 00:19:08.915 [main] DEBUG c.github.pagehelper.PageInterceptor - java.lang.Exception: 设置分页参数时的堆栈信息 at com.github.pagehelper.util.StackTraceUtil.current(StackTraceUtil.java:12) at com.github.pagehelper.Page.(Page.java:111) at com.github.pagehelper.Page.(Page.java:126) at com.github.pagehelper.page.PageMethod.startPage(PageMethod.java:139) at com.github.pagehelper.page.PageMethod.startPage(PageMethod.java:113) at com.github.pagehelper.page.PageMethod.startPage(PageMethod.java:102) at com.github.pagehelper.test.basic.PageHelperTest.testNamespaceWithStartPage(PageHelperTest.java:118) ...omit 00:19:09.069 [main] DEBUG c.g.pagehelper.mapper.UserMapper - Cache Hit Ratio [com.github.pagehelper.mapper.UserMapper]: 0.0 00:19:09.077 [main] DEBUG o.a.i.t.jdbc.JdbcTransaction - Opening JDBC Connection 00:19:09.078 [main] DEBUG o.a.i.t.jdbc.JdbcTransaction - Setting autocommit to false on JDBC Connection [org.hsqldb.jdbc.JDBCConnection@6da21078] 00:19:09.087 [main] DEBUG c.g.p.m.UserMapper.selectAll_COUNT - ==> Preparing: SELECT count(1) FROM user 00:19:09.121 [main] DEBUG c.g.p.m.UserMapper.selectAll_COUNT - ==> Parameters: 00:19:09.131 [main] TRACE c.g.p.m.UserMapper.selectAll_COUNT - <== Columns: C1 00:19:09.131 [main] TRACE c.g.p.m.UserMapper.selectAll_COUNT - <== Row: 183 00:19:09.147 [main] DEBUG c.g.p.m.UserMapper.selectAll_COUNT - <== Total: 1 ``` 2. `dialect` : by default paging will use PageHelper way, if you want to achieve their own paging logic, can realize `Dialect` (`com.github.pagehelper.Dialect`) interface, and then configure the properties to achieve the fully qualified name of the class. 3. `countSuffix` : msId suffix appended when creating or looking for a corresponding count query based on a query, default '_COUNT'. 4. `countMsIdGen`(5.3.2+) : The count method of the msId generation, the default is to query the `msId + countSuffix`, want my own definition, can realize `com.github.pagehelper.CountMsIdGen` interface, the parameter configuration in order to realize the fully qualified class name. A common use: In the case of an Example query, 'selectByExample' can be queried using the corresponding 'selectCountByExample' method. 5. `msCountCache`: Automatically create a query count query method, created the count `MappedStatement` caching, the default will be preferred to find `com.google.common.cache.Cache`. The cache implementation, Projects without Guava dependencies are created using MyBatis' built-in CacheBuilder. Want to fine-grained cache configuration: please refer to the source code. `com.github.pagehelper.cache.CacheFactory`, two configurations of default provides multiple attributes, can also according to the requirements to build themselves here. **The following parameters are the parameters for the default dialect case. When implemented using a custom dialect, the following parameter has no effect.** 1. `helperDialect`: PageHelper will detect the current database url by default, automatically select the corresponding database dialect. You can configure `helperDialect` Property to specify the dialect. You can use the following abbreviations : `oracle`, `mysql`, `mariadb`, `sqlite`, `hsqldb`, `postgresql`, `db2`, `sqlserver`, `informix`, `h2`, `sqlserver2012`, `derby`. You can also implement `AbstractHelperDialect`, and then configure the attribute to achieve the fully qualified class name. **Special note :** When using the SqlServer2012 database, you need to manually specify for `sqlserver2012`, otherwise it will use the SqlServer2005 for paging. 2. `dialectAlias`:Allows you to configure an alias for a custom implementation. It can be used to automatically obtain the corresponding implementation according to JDBCURL. It allows you to override existing implementations in this way. ```xml ``` When you use jdbcurl is not [PageAutoDialect](src/main/java/com/github/pagehelper/page/PageAutoDialect.java) default provide range, can be realized through the change of parameters automatic identification. 3. `useSqlserver2012`(sqlserver):To use the SqlServer2012 database, manually specify SqlServer2012. Otherwise, SqlServer2005 will be used for paging. You can also set `useSqlserver2012=true` to change 2012 to the default mode of SQLServer. 4. `defaultCount`:Use to control whether a count query is executed in a method that does not default to count queries. By default, true executes a count query. This is a globally valid parameter and a uniform behavior across multiple data sources. 5. `countColumn`:Used to configure the query column for automatic count queries. The default value is `0`, which is `count(0)`. The Page object also has a new 'countColumn' parameter, which can be configured for specific queries. 6`offsetAsPageNum`: Default value is `false`, This parameter is valid for `RowBounds` as a pagination parameter. When this parameter is set to `true`, the` offset` parameter in `RowBounds` is used as` pageNum`. 7. `rowBoundsWithCount`: Default value is `false`, When this parameter is set to `true`, PageHelper will execute count query. 8. `pageSizeZero`: Default value is `false`, When this parameter is set to `true`, if `pageSize=0` or `RowBounds.Limit = 0` will query all the results (the equivalent of a Paged query did not execute, but the return type of the result is still `Page`). 9. `reasonable`: Rationalization of paging parameters, Default value is `false`。 When this parameter is set to `true`,` pageNum <= 0` will query the first page, `PageNum> pages` (over the total number), will query the last page. Default `false`, the query directly based on parameters. 10. `params`: In support of `startPage(Object params)` method, The parameter is added to configure the parameter mapping for the value from the object based on the attribute name, you can configure `pageNum,pageSize,count,pageSizeZero,reasonable`, Default value is `pageNum=pageNum;pageSize=pageSize;count=countSql;reasonable=reasonable;pageSizeZero=pageSizeZero`。 11. `supportMethodsArguments`: Support via the Mapper interface parameters to pass the page parameter, the default value is 'false'. The use of methods can refer to the test code in the `com.github.pagehelper.test.basic` package under the` ArgumentsMapTest` and `ArgumentsObjTest`. 12. `autoRuntimeDialect`: Default value is `false`。When set to `true`, it is possible to automatically recognize pagination of the corresponding dialect at run time from multiple data sources (Does not support automatic selection of `sqlserver2012`, can only use` sqlserver`), usage and precautions refer to the following **Scene 5**. 13. `closeConn`: Default value is **`true`**。 When you use a runtime dynamic data source or do not set the `helperDialect` property, PageHelper will automatically get the database type, then a database connection is automatically obtained, This property is used to set whether to close the connection, the default `true` close. When 'false' is set, It will not close the connection. 14. `aggregateFunctions`(5.1.5+): The default is the aggregate function of all common databases, allowing you to manually add aggregate functions ( affecting the number of rows ). All functions that start with aggregate functions will be wrap as subquery. Other functions and columns will be replaced with count(0). 15. `replaceSql`(sqlserver): Optional value of `regex` and `simple`, default value is used when empty `regex` way, also can realize `com.github.pagehelper.dialect.ReplaceSql` interface. 16. `sqlCacheClass`(sqlserver): Used to generate the count and page caching, SQL cache using `com.github.pagehelper.cache.CacheFactory`, optional parameters and the front `msCountCache`. 17. `autoDialectClass`: Add `AutoDialect` interface for automatic access to the database type, can be achieved by `autoDialectClass` configuration for their implementation class, default `DataSourceNegotiationAutoDialect`, priority according to the connection pool. Default implementation, added special handling for 'hikari, Druid, tomcat-JDBC, C3P0, DBCP' type database connection pool, directly from the configuration to get jdbcUrl, when using other types of data sources, still use the old way to get the connection in read jdbcUrl. To use the same method as the old version, you can configure 'autoDialectClass=old'. If the database connection pool type is very clear, you are advised to set it to a specific value. For example, if hikari is used, 'autoDialectClass=hikari' is set. If other connection pools are used, set it to its own implementation class. 18. `boundSqlInterceptors`: Add the `BoundSqlInterceptor` interceptor of the paging plug-in, which can process or simply read SQL in three stages, add the parameter `boundSqlInterceptors`, You can configure multiple implementation class names that implement the BoundSqlInterceptor interface, separated by commas. When PageHelper is called, You can also set this page by using something like `PageHelper.startPage(x,x).boundSqlInterceptor(BoundSqlInterceptor boundSqlInterceptor)`. 19. `keepOrderBy`: Preserves the Order by sort of the query when converting count queries. In addition to global configuration, you can set the parameters for a single operation. 20. `keepSubSelectOrderBy`: Preserves the Order by sort of subqueries when converting count queries. You can avoid adding `/*keep orderby*/` to all subqueries and can set it for a single operation in addition to the global configuration. 21. `sqlParser`: configure JSqlParser parser, attention is `com.github.pagehelper.JSqlParser` interface, used to support such as essentially a need for additional configuration.(**6.1.0 remove this parameter**) #### 6. How to choose Configure these parameters Here are a few examples for some of the parameters may be used. ##### Scene 1 If you are still in with a way to call a namespace like iBATIS, you might use `rowBoundsWithCount`. If you want to count when the paging query query, you need to set this parameter to `true`. **Note:** `PageRowBounds` also need `true`. ##### Scene 2 If you are still in with a way to call a namespace like iBATIS, If you think `RowBounds` in the two parameters` offset, limit` not as good as `pageNum, pageSize` easy to understand. You can use the `offsetAsPageNum` parameter, when the parameter is set to `true`, `offset` as `pageNum`, `limit` and `pageSize` mean the same thing. ##### Scene 3 If you feel you have to paginate a page somewhere and you still want to query all the results with control parameters. You can configure `pageSizeZero` to` true`, After configuration, when `pageSize = 0` or `RowBounds.limit = 0` will query all the results. ##### Scene 4 If you want the user to enter the page number is not in the legal scope (the first page to the last page) to correctly respond to the correct results page, Then you can configure `reasonable` to` true`, and if `pageNum <= 0` will query the first page, the `pageNum> pages(total pages)` will query the last page. ##### Scene 5 If you configure dynamic data sources in Spring and connect different types of databases, you can configure `autoRuntimeDialect` to` true`, which will use matching pagination queries when using different data sources. In this case, you also need to pay attention to the `closeConn` parameter, because the type of access to the data source will get a database connection, so the need to control this parameter to obtain a connection, whether to close the connection. Default is `true`, and some database connections can not be closed after the follow-up database operations. And some database connections will not be closed soon because the number of connections out of the database caused no response. Therefore, when using this feature, in particular, you need to pay attention to whether the use of the data source needs to close the database connection. When you do not use dynamic data sources but only automatically get `helperDialect`, the database connection will only get once, so there is no need to worry about whether this connection will lead to a database error, but also according to the characteristics of the data source to choose whether to close the connection. ### 3. How to use in your code Please note before reading [Important Notice](https://github.com/pagehelper/Mybatis-PageHelper/blob/master/wikis/en/Important.md) PageHelper supports the following usage: ```java //1. use by RowBounds List list = sqlSession.selectList("x.y.selectIf", null, new RowBounds(0, 10)); //or interface List list = userMapper.selectIf(1, new RowBounds(0, 10)); //or PageRowBounds PageRowBounds rowBounds = new PageRowBounds(0, 10); List list = userMapper.selectIf(1, rowBounds); long total = rowBounds.getTotal(); //2. use static method startPage PageHelper.startPage(1, 10); List list = userMapper.selectIf(1); //3. use static method offsetPage PageHelper.offsetPage(0, 10); List list = userMapper.selectIf(1); //4. method parameters public interface CountryMapper { List selectByPageNumSize( @Param("user") User user, @Param("pageNum") int pageNum, @Param("pageSize") int pageSize); } //config supportMethodsArguments=true List list = userMapper.selectByPageNumSize(user, 1, 10); //5. POJO parameters public class User { //other fields //The following two parameters must be the same name as the params parameter private Integer pageNum; private Integer pageSize; } public interface CountryMapper { List selectByPageNumSize(User user); } //When the pageNum! = null && pageSize! = null in the user instance, this method will be automatically pagination List list = userMapper.selectByPageNumSize(user); //6. ISelect interface //jdk6,7 anonymous class, return Page Page page = PageHelper.startPage(1, 10).doSelectPage(new ISelect() { @Override public void doSelect() { userMapper.selectGroupBy(); } }); //jdk8 lambda Page page = PageHelper.startPage(1, 10).doSelectPage(()-> userMapper.selectGroupBy()); //return PageInfo pageInfo = PageHelper.startPage(1, 10).doSelectPageInfo(new ISelect() { @Override public void doSelect() { userMapper.selectGroupBy(); } }); //in lambda pageInfo = PageHelper.startPage(1, 10).doSelectPageInfo(() -> userMapper.selectGroupBy()); //do count only long total = PageHelper.count(new ISelect() { @Override public void doSelect() { userMapper.selectLike(user); } }); //lambda total = PageHelper.count(()->userMapper.selectLike(user)); ``` Introduced The most common ways. #### 1). RowBounds and PageRowBounds ```java List list=sqlSession.selectList("x.y.selectIf",null,new RowBounds(1,10)); ``` Using this method, you can use the Row Bounds parameter for paging, which is the least invasive method. As we can see, the call using the Row Bounds parameter doesn't add anything else. When the paging plug-in detects that the Row Bounds parameter is used, the query is physically paginated. There are two special arguments to RowBounds for this method of calling. You can see Scene 1 and 2 above **Note:** You can use Row Bounds not only in namespace mode, but also when using an interface. For example: ```java //A physical paging query is also performed in this case List selectAll(RowBounds rowBounds); ``` **Note:** Since RowBounds by default does not get the total number of queries, the PageRowBounds plug-in provides a ' PageRowBounds' object that inherits from RowBounds. The' Total 'property is added to this object to get the total number of queries after performing a pagination query. #### 2). `PageHelper.startPage` Static method calls In addition to the `PageHelper.startPage` method, the `PageHelper.offsetPage` method is also provided. Call the `PageHelper.startPage` static method before the MyBatis query method that you want to page. The first MyBatis query method immediately following this method will be paginated. ##### Example 1: ```java //Get page 1, 10 items, default query total count PageHelper.startPage(1,10); //The first SELECT method immediately following is paginated List list=userMapper.selectIf(1); assertEquals(2, list.get(0).getId()); assertEquals(10,list.size()); //When paging, the actual returned result list type is Page. If you want to take out paging information, you need to force the conversion to Page. assertEquals(182,((Page)list).getTotal()); ``` ##### Example 2: ```java //request: url?pageNum=1&pageSize=10 //Supports ServletRequest,Map,POJO objects, and PARams parameters PageHelper.startPage(request); //The first SELECT method immediately following is paginated List list = userMapper.selectIf(1); //Subsequent pages will not be paginated unless Page helper.start Page is called again List list2 = userMapper.selectIf(null); //list1 assertEquals(2, list.get(0).getId()); assertEquals(10, list.size()); //During paging, the actual returned result list type is Page. If you want to take out paging information, you need to force conversion to Page. //Or use the Page Info class (described in the example below) assertEquals(182, ((Page) list).getTotal()); //list2 assertEquals(1, list2.get(0).getId()); assertEquals(182, list2.size()); ``` ##### Example 3,Use `PageInfo`: ```java //Get page 1, 10 items, default query total count PageHelper.startPage(1,10); List list=userMapper.selectAll(); //Wrap the results with Page Info PageInfo page=new PageInfo(list); //Test all Page Info properties //Page Info contains a very comprehensive set of paging properties assertEquals(1,page.getPageNum()); assertEquals(10,page.getPageSize()); assertEquals(1,page.getStartRow()); assertEquals(10,page.getEndRow()); assertEquals(183,page.getTotal()); assertEquals(19,page.getPages()); assertEquals(1,page.getFirstPage()); assertEquals(8,page.getLastPage()); assertEquals(true,page.isFirstPage()); assertEquals(false,page.isLastPage()); assertEquals(false,page.isHasPreviousPage()); assertEquals(true,page.isHasNextPage()); ``` #### 3). Using parameters To use the parametric approach, you need to set the `supportMethodsArguments` parameter to `true`, as well as the `params` parameter. For example, the following configuration: ```xml ``` In the MyBatis method: ```java List selectByPageNumSize( @Param("user") User user, @Param("pageNumKey") int pageNum, @Param("pageSizeKey") int pageSize); ``` When this method is called, it is paged because both `pageNumKey` and `pageSizeKey` arguments are found. Several parameters provided by PARams can be used in this way. In addition to the above method, if the User object contains these two parameter values, you can also have the following method: ```java List selectByPageNumSize(User user); ``` When both `pageNumKey` and `pageSizeKey` arguments are found from User, the method is paged. Note: The presence of both `pageNum` and `pageSize` will trigger the paging operation. In this case, the other paging parameters will take effect. #### 3). `PageHelper` Safety call ##### 1. Using the RowBounds and PageRowBounds arguments is extremely safe ##### 2. The parametric approach is extremely safe ##### 3. The call using the `ISelect` interface is extremely secure In addition to being secure, the ISelect interface specifically converts the query to a simple count query, which converts any query method into a `select count(*)` query method. ##### 4. When does this lead to unsafe paging? The `PageHelper` method uses a static `ThreadLocal` argument, and the page argument is bound to the thread. This is safe as long as you can ensure that the MyBatis query method is followed by the `PageHelper` method call. Because PageHelper automatically clears objects stored in ThreadLocal in the Finally section. If an exception occurs before the code enters the Executor, the thread is not available. This is an artificial Bug (for example, when an interface method does not match an XML method and a 'MappedStatement' is not found). It does not cause the ThreadLocal argument to be used incorrectly. But if you write code like this, it is not safe to use it: ```java PageHelper.startPage(1, 10); List list; if(param1 != null){ list = userMapper.selectIf(param1); } else { list = new ArrayList(); } ``` In this case, because param1 is null, it causes PageHelper to produce a page parameter, but it is not consumed, so it remains on the thread. When this thread is used again, it may cause the paging parameter to be consumed by a method that should not be paged, resulting in unexplained paging. The above code should look like this: ```java List list; if(param1 != null){ PageHelper.startPage(1, 10); list = userMapper.selectIf(param1); } else { list = new ArrayList(); } ``` It's safe to write it this way. If you're worried about this, you can manually clean up the paging parameters stored in ThreadLocal by using the following: ```java List list; if(param1 != null){ PageHelper.startPage(1, 10); try{ list = userMapper.selectAll(); } finally { PageHelper.clearPage(); } } else { list = new ArrayList(); } ``` It's not pretty, and it's unnecessary. ### 4. MyBatis and Spring integration example If you are not familiar with Spring integration, you can refer to the following two There is only basic configuration information, without any off-the-shelf functionality, as a starting point for building the framework - [integration Spring 3.x](https://github.com/abel533/Mybatis-Spring/tree/spring3.x) - [integration Spring 4.x](https://github.com/abel533/Mybatis-Spring) ### 5. Spring Boot integration example - [pagehelper-spring-boot-samples](https://github.com/pagehelper/pagehelper-spring-boot/tree/master/pagehelper-spring-boot-samples) - https://github.com/abel533/MyBatis-Spring-Boot ================================================ FILE: wikis/en/Important.md ================================================ ## Important Note ### `PageHelper.startPage` method important tips Only the first Mybatis query (select) method immediately after the `PageHelper.startPage` method will be paged. ### Please do not configure more than one PageHelper When using Spring, you can config PageHelper by `mybatis-config.xml` or `Spring`. Select one of them, do not configure PageHelper in two ways at the same time. ### PageHelper does not support paging with `for update` statement ### PageHelper does not support Nested Results Mapping Since the nested result mode causes the resultSet to be folded, the total number of results for the paged query will decrease after folding. So It cannot guarantee the number of paged results correctly. ================================================ FILE: wikis/en/Test.md ================================================ ## Test In order to guarantee the stability of PageHelper, the project contains a large number of unit tests, and can be tested for supported databases. ### Multi database test To make it easier to test different databases, add a different database mybatis configuration file to the `src/test/resources` directory, and modify the configuration in `test.properties` so that the tests can be tested with different configurations. In order to make it easier to test different database, there are many different mybatis profile in the `src/test/resources` directory. By modifying the `test.properties` allows you to test different databases. `test.properties`: ```properties # Need to configure the corresponding database first # Write the database name which you want to test # Optional values as following #hsqldb #mysql #mariadb - Note In the config files, database port is 3309 #oracle #postgresql #sqlserver #db2 #h2 #derby database = hsqldb ``` ================================================ FILE: wikis/zh/Changelog.md ================================================ ## 更新日志 ### 6.1.1 - 2025-06-20 - 新增对 SunDB 数据库的分页功能支持 **by wangsl** - 新增对 Xugu(虚谷数据库)的适配支持 **by 吴启洋** - 修复在复制 `countBoundSql` 时未正确复制 `additionalParameter` 的问题 **by yefeng** - 修复 `offsetPage` 示例代码错误 **by S00ahKim** - 修复 Jakarta/Javax ServletRequest 兼容性问题,支持 Spring Boot 3.x **by PING** - 新增 `PageInfo.of()` 重载方法,支持手动指定查询记录总数返回分页信息 **by yesAnd** - 升级 MyBatis 版本至 3.5.19(从 3.5.10) - 升级 Guava 版本至 33.4.8-jre(从 32.0.0-jre) - 升级 Logback Classic 版本至 1.2.13(从 1.2.11) - 优化 Xugu JDBC 依赖配置,添加 `test` - 修复英文文档中的拼写错误和链接引用 **by Coco Liliace** - 补充相关注释信息,提高代码可读性 **by yesAnd** - 解决依赖安全漏洞,更新相关组件版本 #### 兼容性说明 - 本版本与之前版本保持向后兼容 - 新增数据库支持:SunDB、Xugu(虚谷数据库) - 修复了 Spring Boot 3.x 兼容性问题,建议使用 Jakarta EE 的用户升级 #### 升级建议 - 所有用户建议升级,特别是使用 Spring Boot 3.x 或需要新数据库支持的用户 - 使用 SunDB 或虚谷数据库的用户可以直接使用分页功能 - 升级前请确保相关依赖版本兼容性 ### 6.1.0 - 2023-12-16 - 发布6.1.0,PageHelper 提供 jsqlparser直接依赖都是中间接口,可以通过SPI替换默认实现 - 升级jsqlparser版本4.7,重新实现order by,分页,count查询 - 简化pom.xml配置,去掉shade内嵌jsqlparser方式,改为通过外部依赖选择不同的jsqlparser版本,允许自己SPI扩展 - jsqlparser解析不使用线程池,支持SPI扩展覆盖SqlParser实现 - SqlServer分页改为SqlServerSqlParser接口,添加参数 sqlServerSqlParser 覆盖默认值 - OrderByParser提取OrderBySqlParser接口,增加 orderBySqlParser 参数,可以覆盖默认实现 - OrderByParser静态方法改为普通方法,为后续改接口做准备 - jdk8+后不再需要JSqlParser接口,移除该接口,文档标记该参数(_该参数早期用于支持sqlserver特殊配置_) 兼容jsqlparser4.7版本 - maven-compiler-plugin固定版本以去除警告,并增加构建稳定性 qxo - gitignore .vscode for vscode ide qxo - 修改bug https://github.com/pagehelper/Mybatis-PageHelper/issues/779 chenyuehui 为了兼容 jsqlparser 4.5 和 4.7,以及后续可能存在的其他版本,新建了一个 pagehelper-sqlparser 项目,目前提供了 4.5 和 4.7 两个实现, 使用时从 pagehelper 排除 jsqlparser,然后选择一个 jsqlparser 实现即可,当前版本默认使用的 4.7 版本的代码, 因此如果想换 4.5 的实现,可以按照下面方式进行配置: ```xml com.github.pagehelper pagehelper 6.1.0 com.github.jsqlparser jsqlparser com.github.pagehelper sqlparser4.5 6.1.0 ``` SPI 替换默认值的优先级低于 `sqlServerSqlParser`,`orderBySqlParser`,`countSqlParser` 参数指定的实现,不指定时如果存在SPI实现,即可生效, SPI 可以参考 pagehelper-sqlsource 模块代码。 JSqlParser 默认解析 SQL 会使用临时创建的 `Executors.newSingleThreadExecutor()`,这里通过 API 跳过了线程池: ```java CCJSqlParser parser = CCJSqlParserUtil.newParser(statementReader); parser.withSquareBracketQuotation(true); return parser.Statement(); ``` JSqlParser 使用线程池的目的是为了防止解析超时,因此如果你遇到过超时的情况,可以引入下面的依赖(通过SPI覆盖了默认实现,超时时间10秒): ```xml com.github.pagehelper sqlparser-timeout 6.1.0 ``` ### 6.0.0 - 2023-11-05 - 基于jdk8适配,6.0开始不支持jdk6和7,如果有需要可以使用5.x版本 - 增加异步count支持,全局配置`asyncCount`,默认`false`,单次设置:`PageHelper.startPage(1, 10).enableAsyncCount()`; 异步使用独立连接(事务)查询,有增删改操作影响查询时不适合开启异步查询。closed #334 - JSqlParser默认开启 `parser.withSquareBracketQuotation(true)`,支持 SqlServer `[]` - feat: 在`PageInfo`类中新增了用以进行数据对象转换的方法 ` PageInfo convert(Page.Function function)` **by codeke** - `CountSqlParser`改为接口,允许通过`countSqlParser`参数替换为自己的实现,支持 #772 - `dialectAlias`支持简化配置,例如`dm=oracle;oracle=oracle9i`,直接引用现在的缩写,不用写类全名 - `countColumn`添加注入检测,fixed #686 - 增加`PageParam`类,不内嵌对象(会影响使用),如果想用可以继承该对象,closed #562 - 所有异常信息改为英文提示 - 放开 `setLocalPage`,支持 #771 - 解决`sqlserver`带union sql解析时处理order by错误的问题,fixed #768 - 优化total逻辑,解决指定不分页查询,同时指定order by时无效的问题,fixed #641 - 修改 dialect 实例化逻辑,保证类完成配置后使用,fixed #742 - `dialectAliasMap`改为`LinkedHashMap`,可以按配置顺序进行匹配,fixed #758 - 行云数据库分页BUG修复 **by maimaitiyaer_bonc** ### 5.3.3 - 2023-06-03 - Ignoring unnecessarily generated surefire-report **by java-codehunger** - 支持从URL中解析openGauss 数据库 对应的方言 **by saxisuer** - 修复sql注入检验不正确问题 #716 **by uyong** - 支持从url中解析人大金仓kingbase8对应的方言 **by univ** - 添加支持cirrodata的分页 #705 **by sxh0570** ### 5.3.2 - 2022-09-18 - 使用文档更新,所有参数都包含在内,首页默认文档改为中文。 - Add support for kingbase. by **HanHuimin001** - 增加 `debug` 参数,默认 `false`,为`true`时开启`debug`模式,开始 `debug` 模式后将记录调用堆栈 by **huyingqian** - Add 支持count的sql支持hint语法 by **zhanliquan** - 增加 `PageProperties` 接口,框架内部实例化的扩展类如果实现了这个接口,可以通过这个接口的方法获取分页插件配置。 - 增加 `CountMsIdGen` 接口,可以通过 `countMsIdGen` 配置自定义实现类,该类用于生成查询对应COUNT查询的msId。默认实现还是使用`countSuffix` ,通过扩展可以实现如 `selectByExample` 映射到对应的 `selectCountByExample` 方法。 - 增加 `keepOrderBy` 和 `keepSubSelectOrderBy` 配置。 - 增加 `sqlParser` 配置,增加 `JSqlParser` 接口,解决 jsqlparser 和 jdk 兼容性导致无法额外配置的问题(**6.1.0 移除该参数 **)。 - 测试使用 logback 日志框架,去掉log4j。 - 解决 `dialectKey` 为空导致NPE,fixed #656 关于以上参数的详细介绍,请查看 [如何使用分页插件](HowToUse.md)。 ### 5.3.1 - 2022-06-14 - 处理 CVE-2022-28111 漏洞,限制 order by 参数,避免 SQL 注入 - Add support for as400. **by bluezealot** - 优化分页结果包装类的泛型参数 **by 章福来** - 规范PostgreSQL分页参数的顺序 **by outian** ### 5.3.0 - 2021-10-07 - 增加 `AutoDialect` 接口用于自动获取数据库类型,可以通过 `autoDialectClass` 配置为自己的实现类,默认使用 `DataSourceNegotiationAutoDialect`,优先根据连接池获取。 默认实现中,增加针对 `hikari,druid,tomcat-jdbc,c3p0,dbcp` 类型数据库连接池的特殊处理,直接从配置获取jdbcUrl,当使用其他类型数据源时,仍然使用旧的方式获取连接在读取jdbcUrl。 想要使用和旧版本完全相同方式时,可以配置 `autoDialectClass=old`。当数据库连接池类型非常明确时,建议配置为具体值,例如使用 hikari 时,配置 `autoDialectClass=hikari` ,使用其他连接池时,配置为自己的实现类。 - 支持运行时动态指定使用的 dialect 实现,例如 `PageHelper.startPage(1, 10).using("oracle");` 或者 `PageHelper.startPage(2, 10).using("org.exmaple.CustomDialect");` - `PageInfo` 增加空实例常量属性 `PageInfo.EMPTY` 以及内容判断 `boolean hasContent()`。 - 启动中增加 banner, 需要日志级别 debug,可以通过 `-Dpagehelper.banner=false` 或者环境变量 `PAGEHELPER_BANNER=false` 关闭 ``` DEBUG [main] - ,------. ,--. ,--. ,--. | .--. ' ,--,--. ,---. ,---. | '--' | ,---. | | ,---. ,---. ,--.--. | '--' | ' ,-. | | .-. | | .-. : | .--. | | .-. : | | | .-. | | .-. : | .--' | | --' \ '-' | ' '-' ' \ --. | | | | \ --. | | | '-' ' \ --. | | `--' `--`--' .`- / `----' `--' `--' `----' `--' | |-' `----' `--' `---' `--' is intercepting. ``` 增加 banner 的目的在于,如果你配置了多次分页插件,你会看到 banner 输出多次,你可以在 `PageInterceptor` 构造方法断点看看那些地方进行了实例化。 - 完善 Count 查询,当存在 having 时,不在优化查询列。查询列存在有别名的函数或者运算时也不优化查询列,避免 order by 或 having 中使用的别名不存在。 - 增加判断处理某些数据(如 TDEngine)查询 count 无结果时返回 null - 添加 Firebird 数据库支持和 SqlServer2012 分页语法相同。 - 添加 impala 数据库自动识别。 - JSqlParser 升级为 4.2 版本。 > 距离上次更新3个月左右,这次更新直接让假期少了3天 :running: ,关了 GitHub 和 Gitee 上的 200 多个issue,不一定所有问题都得到了处理,如果你还有疑问,可以继续提 issue,下个大版本会考虑直接 6.0,计划全部升级到 java 8,功能保持不变。 ### 5.2.1 - 2021-06-20 - 升级依赖 jsqlparser 4.0, mybatis 3.5.7 - 自动识别以下数据库: - 虚谷数据库 xugu #599 - 神通数据库 oscar by **ranqing** - 瀚高数据库 highgo by **ashaiqing** - BoundSqlInterceptorChain拦截器index参数bug, fixed #587 - fixed #558 - 添加 PostgreSQL 方言 by **liym@home** - fixed #604, 解决total丢失的问题 - 规范注释, fixed #547 ### 5.2.0 - 2020-07-26 - jsqlparser升级到3.2版本,sql解析更好,对sqlserver支持更好。 - 修改 sqlserver 方式中的替换正则,现在允许 with( nolock ) 括号中存在空格。 - 解决 reasonable 和 pageSizeZero,以及 offset 用法中的bug,现在的含义和结果更一致。 - 分页 SQL 拼接过程中增加换行符,避免原始 SQL 中存在注释导致分页部分无效。 - Oracle 和 Db2 中的行号 ROW_ID 别名改为 PAGEHELPER_ROW_ID,避免和常用名称冲突。 - 解决单个参数ProviderSql使用其他拦截器时的特殊问题(支持 mybatis 3.4.0+)[by 罗震宇](https://github.com/luozhenyu) - 支持自动识别 clickhouse,使用 MySQL 方式进行分页。 - 将 startRow, endRow 类型从 int 改为 long。 - Page 增加 `public PageInfo toPageInfo(Function function)` 方法,用于转换查询结果中的数据。 - 参考 pr#476 提供 `·`Oracle9iDialect`,这也是曾经用过的一种分页方式,可以自己测试选择合适的分页方式。 目前提供的两种 Oracle 分页如下: ```sql -- OracleDialect 外层控制范围 WHERE ROW_ID <= ? AND ROW_ID > ? -- Oracle9iDialect 内外分别控制范围 TMP_PAGE WHERE ROWNUM <= ? ) WHERE ROW_ID > ? ``` - 增加分页插件的 `BoundSqlInterceptor` 拦截器,可以在3个阶段对 SQL 进行处理或者简单读取, 增加参数 `boundSqlInterceptors`,可以配置多个实现 `BoundSqlInterceptor` 接口的实现类名, 使用英文逗号隔开。PageHelper调用时,也可以通过类似 `PageHelper.startPage(x,x).boundSqlInterceptor(BoundSqlInterceptor boundSqlInterceptor)`针对本次分页进行设置。 本次更新最大的变化是增加了 `BoundSqlInterceptor`,通过该接口可以在运行时拦截分页处理的 SQL(BoundSQL对象): ```java /** * BoundSql 处理器 */ public interface BoundSqlInterceptor { /** * boundsql 处理 * * @param type 类型 * @param boundSql 当前类型的 boundSql * @param cacheKey 缓存 key * @param chain 处理器链,通过 chain.doBoundSql 方法继续执行后续方法,也可以直接返回 boundSql 终止后续方法的执行 * @return 允许修改 boundSql 并返回修改后的 */ BoundSql boundSql(Type type, BoundSql boundSql, CacheKey cacheKey, Chain chain); enum Type { /** * 原始SQL,分页插件执行前,先执行这个类型 */ ORIGINAL, /** * count SQL,第二个执行这里 */ COUNT_SQL, /** * 分页 SQL,最后执行这里 */ PAGE_SQL } /** * 处理器链,可以控制是否继续执行 */ interface Chain { Chain DO_NOTHING = new Chain() { @Override public BoundSql doBoundSql(Type type, BoundSql boundSql, CacheKey cacheKey) { return boundSql; } }; BoundSql doBoundSql(Type type, BoundSql boundSql, CacheKey cacheKey); } } ``` 接口中包含了 boundSql 接口方法,还有 Type 枚举,和 Chain 接口的定义,自己实现的时候不需要考虑 Chain。 通过 `boundSqlInterceptors` 参数配置拦截器,执行时存在下面三种情况: 1. 不管当前执行的 SQL 是否会分页,都会执行 `Type.ORIGINAL` 类型的拦截器方法,配置后一定会执行。 2. 调用分页方法时,拦截器会继续执行 `Type.COUNT_SQL` 类型的拦截器方法,这个方法只有执行分页并且指定要进行 count 查询时才会执行。 3. 调用分页方法时,如果 count > 0,就会执行 `Type.PAGE_SQL` 类型的拦截器方法,这个方法只有执行分页时才会执行。 > 通过 `PageHelper.startPage(1, Integer.MAX_VALUE, false).boundSqlInterceptor(BoundSqlInterceptor boundSqlInterceptor)` > 这种指定的参数时,也能起到不进行分页和count查询,但是可以执行 `Type.ORIGINAL` 类型的拦截器方法。 当前拦截器在整个分页执行过程中,会执行3次,对应 Type 枚举的 3 个类型,执行顺序也一致。 如果想获取分页 SQL 执行前的,只需要关注 Type.ORIGINAL,另外两种就是 count 执行前和分页执行前(count=0时分页方法不执行,这里也不会执行)。 以测试代码为例: ```java public class TestBoundSqlInterceptor implements BoundSqlInterceptor { public static final String COMMENT = "\n /* TestBoundSqlInterceptor */\n"; @Override public BoundSql boundSql(Type type, BoundSql boundSql, CacheKey cacheKey, Chain chain) { if (type == Type.ORIGINAL) { String sql = boundSql.getSql(); MetaObject metaObject = MetaObjectUtil.forObject(boundSql); metaObject.setValue("sql", sql + COMMENT); } return chain.doBoundSql(type, boundSql, cacheKey); } } ``` 上面这段代码在 sql 执行前先修改原始 SQL,只是在最后增加了一段注释,不影响 SQL 执行,通过下面的方式配置: ```xml ``` 这里为了说明该参数值可以是多个,因此重复配置了一次,也就是上面的拦截器会执行两次。 这样配置后,上面的 SQL 在分页执行的时候就会修改 SQL。 除了这种配置方式外,还支持 PageHelper.startPage 时临时指定,这种方式会把拦截器放到链头先执行,因此可以控制后续的是否执行,也可以在后续所有执行外,做最后处理再返回。 示例: ```java PageHelper.startPage(1, 10).boundSqlInterceptor(new BoundSqlInterceptor() { @Override public BoundSql boundSql(Type type, BoundSql boundSql, CacheKey cacheKey, Chain chain) { System.out.println("before: " + boundSql.getSql()); BoundSql doBoundSql = chain.doBoundSql(type, boundSql, cacheKey); System.out.println("after: " + doBoundSql.getSql()); if (type == Type.ORIGINAL) { Assert.assertTrue(doBoundSql.getSql().contains(TestBoundSqlInterceptor.COMMENT)); } return doBoundSql; } }); ``` ### 5.1.11 - 2019-11-26 - 增加神通数据库的支持 **wangss** - Add support for HerdDB - support HerdDB, mostly like MySQL - auto detect HerdDB **Enrico Olivelli** - fix some typos and grammar issues **LHearen** ### 5.1.10 - 2019-06-05 在 *5.1.0 - 2017-08-28* 版本中,增加 `ReplaceSql` 接口用于处理 sqlServer 的 `with(nolock)` 问题,增加了针对性的 `replaceSql` 参数, 可选值为 `simple` 和 `regex`,或者是实现了ReplaceSql接口的全限定类名。默认值为 `simple`,仍然使用原来的方式处理, 新的 `regex` 会将如 `table with(nolock)` 处理为 `table_PAGEWITHNOLOCK`。 本次更新仅仅是把默认值从 `simple` 改为了 `regex`,使用 `regex` 方式几乎能 100% 解决 sqlServer 的分页问题。 下面是两个 issue 中的示例。 #### 示例 SQL [#76](https://github.com/pagehelper/pagehelper-spring-boot/issues/76) 原始 SQL: ```sql SELECT * FROM forum_post_info a with(nolock) LEFT JOIN forum_carcase_tags as b with(nolock) on a.id = b.carcase_id where b.tag_id = 127 ``` 转换的 Count SQL: ```sql SELECT COUNT(0) FROM forum_post_info a WITH (NOLOCK) LEFT JOIN forum_carcase_tags b WITH (NOLOCK) ON a.id = b.carcase_id WHERE b.tag_id = 127 ``` 转换的分页 SQL: ```sql SELECT TOP 10 * FROM ( SELECT ROW_NUMBER() OVER (ORDER BY RAND()) AS PAGE_ROW_NUMBER, * FROM ( SELECT * FROM forum_post_info a WITH (NOLOCK) LEFT JOIN forum_carcase_tags b WITH (NOLOCK) ON a.id = b.carcase_id WHERE b.tag_id = 127 ) PAGE_TABLE_ALIAS ) PAGE_TABLE_ALIAS WHERE PAGE_ROW_NUMBER > 1 ORDER BY PAGE_ROW_NUMBER ``` #### 示例 SQL [#398](https://github.com/pagehelper/Mybatis-PageHelper/issues/398) 原始 SQL: ```sql Select AUS.ScheduleID, AUS.SystemID, AUS.ClinicID, AUS.DoctorID, AUS.ScheduleDate, AUS.StartTime, AUS.EndTime, AUS.Status, AUS.BookBy, AUS.Note, AUS.Remark, AUS.SourceType, CM.CompanyName, AU.UserName As DoctorName, AU.UserNumber As DoctorNumber, CC.CodeDesc As ClinicName, CD.Lat, CD.Lng, CD.ContactTel, CD.Address, CR.ConsultationStatusID, CR.RegisterStatus,A1.CodeDesc as AreaLevel1, A2.CodeDesc as AreaLevel2 From ACM_User_Schedule AUS with(nolock) Left Join Client_Register CR with(nolock) On AUS.BookBy=CR.ClientID And CR.SourceType='F' And AUS.ClientRegisterNum=CR.ClientRegisterNum Inner Join ACM_User AU with(nolock) On AU.UserID = AUS.DoctorID Inner Join Code_Clinic CC with(nolock) On AUS.ClinicID=CC.CodeID Inner Join Clinic_Detail CD with(nolock) On CC.CodeID = CD.ClinicID Inner Join Code_Area A1 with(nolock) On CD.AreaLevel1ID=A1.CodeID Inner Join Code_Area A2 with(nolock) On CD.AreaLevel2ID=A2.CodeID Inner Join Company_Master CM with(nolock) On CC.SystemID = CM.SystemID Where BookBy=1 ``` 转换的 Count SQL: ```sql SELECT COUNT(0) FROM ACM_User_Schedule AUS WITH (NOLOCK) LEFT JOIN Client_Register CR WITH (NOLOCK) ON AUS.BookBy = CR.ClientID AND CR.SourceType = 'F' AND AUS.ClientRegisterNum = CR.ClientRegisterNum INNER JOIN ACM_User AU WITH (NOLOCK) ON AU.UserID = AUS.DoctorID INNER JOIN Code_Clinic CC WITH (NOLOCK) ON AUS.ClinicID = CC.CodeID INNER JOIN Clinic_Detail CD WITH (NOLOCK) ON CC.CodeID = CD.ClinicID INNER JOIN Code_Area A1 WITH (NOLOCK) ON CD.AreaLevel1ID = A1.CodeID INNER JOIN Code_Area A2 WITH (NOLOCK) ON CD.AreaLevel2ID = A2.CodeID INNER JOIN Company_Master CM WITH (NOLOCK) ON CC.SystemID = CM.SystemID WHERE BookBy = 1 ``` 转换的分页 SQL: ```sql SELECT TOP 10 ScheduleID, SystemID, ClinicID, DoctorID, ScheduleDate , StartTime, EndTime, Status, BookBy, Note , Remark, SourceType, CompanyName, DoctorName, DoctorNumber , ClinicName, Lat, Lng, ContactTel, Address , ConsultationStatusID, RegisterStatus, AreaLevel1, AreaLevel2 FROM ( SELECT ROW_NUMBER() OVER (ORDER BY RAND()) AS PAGE_ROW_NUMBER, ScheduleID, SystemID, ClinicID, DoctorID , ScheduleDate, StartTime, EndTime, Status, BookBy , Note, Remark, SourceType, CompanyName, DoctorName , DoctorNumber, ClinicName, Lat, Lng, ContactTel , Address, ConsultationStatusID, RegisterStatus, AreaLevel1, AreaLevel2 FROM ( SELECT AUS.ScheduleID, AUS.SystemID, AUS.ClinicID, AUS.DoctorID, AUS.ScheduleDate , AUS.StartTime, AUS.EndTime, AUS.Status, AUS.BookBy, AUS.Note , AUS.Remark, AUS.SourceType, CM.CompanyName, AU.UserName AS DoctorName, AU.UserNumber AS DoctorNumber , CC.CodeDesc AS ClinicName, CD.Lat, CD.Lng, CD.ContactTel, CD.Address , CR.ConsultationStatusID, CR.RegisterStatus, A1.CodeDesc AS AreaLevel1, A2.CodeDesc AS AreaLevel2 FROM ACM_User_Schedule AUS WITH (NOLOCK) LEFT JOIN Client_Register CR WITH (NOLOCK) ON AUS.BookBy = CR.ClientID AND CR.SourceType = 'F' AND AUS.ClientRegisterNum = CR.ClientRegisterNum INNER JOIN ACM_User AU WITH (NOLOCK) ON AU.UserID = AUS.DoctorID INNER JOIN Code_Clinic CC WITH (NOLOCK) ON AUS.ClinicID = CC.CodeID INNER JOIN Clinic_Detail CD WITH (NOLOCK) ON CC.CodeID = CD.ClinicID INNER JOIN Code_Area A1 WITH (NOLOCK) ON CD.AreaLevel1ID = A1.CodeID INNER JOIN Code_Area A2 WITH (NOLOCK) ON CD.AreaLevel2ID = A2.CodeID INNER JOIN Company_Master CM WITH (NOLOCK) ON CC.SystemID = CM.SystemID WHERE BookBy = 1 ) PAGE_TABLE_ALIAS ) PAGE_TABLE_ALIAS WHERE PAGE_ROW_NUMBER > 1 ORDER BY PAGE_ROW_NUMBER ``` SQL 经过 https://tool.oschina.net/codeformat/sql 格式化。 ### 5.1.9 - 2019-05-29 - 升级 jsqlparser 为 2.0,升级 mybatis 为 3.5.1,解决兼容性问题。 - 完善分页逻辑判断,fixed #389 - 解决 MetaObject 版本兼容性问题 fixed #349 - 处理 order by 解析失败时输出警告日志,不在抛出异常 - 解决三处可能会导致countColumn失效的问题 fixed #325 - 解决 BIT_ 少的逗号 fixed #341 - 处理文档中的失效链接 isea533 - 文档示例错误,fixed #366 - fixed #373 NPE 问题 ### 5.1.8 - 2018-11-11 - 解决 sqlserver 中 with(nolock) 的问题([#pr10](https://gitee.com/free/Mybatis_PageHelper/pulls/10)) by [lvshuyan](https://gitee.com/lvshuyan) ### 5.1.7 - 2018-10-11 - 增加对阿里云PPAS数据库的支持,自动识别edb,fixed #281 ### 5.1.6 - 2018-09-05 - 增加参数 useSqlserver2012,设置为 true 后,使用 sqlserver2012(Dialect) 作为 SqlServer 数据库的默认分页方式,这种情况在动态数据源时方便使用。默认使用的低版本(05,08)分页方式。 - 增加 IPage 接口,目前支持 mybatis 查询方法只有一个参数,并且参数实现 IPage 接口时,如果存在分页参数,就会自动进行分页查询。感谢 [moonfruit](https://github.com/moonfruit) 两年前的 issue。 - 解决 HashSet 并发问题 fixed #276 - 优化代码结构,精简拦截器代码 ### 5.1.5 - 2018-09-02 - 优化代码,去掉没必要的校验(**by lenosp**) - 解决 pageKey 多处理一次的小问题 #268 - 新增 gitee 提供的 javadoc 文档(https://apidoc.gitee.com/free/Mybatis_PageHelper) - 解决默认反射不带缓存的问题 fixed #275 - 优化mysql ifnull函数导致分页性能问题 (**by miaogr**)(这个修改最终改成了下面的 `aggregateFunctions`) - jsqlparser 升级为 1.2 版本,和 1.0 有不兼容的情况,已经解决。 fixed 273 - 去掉 PageInfo 中存在歧义的 g(s)etFirstPage 和 g(s)etLastPage 两个方法 - 抛出排序时解析失败的异常 fixed #257 - 解决 Spring `` 方式配置时,没有 `properties` 属性时的初始化问题 fixed #26 - 修复Oracle分页会漏查数据的问题 (**by muyun12**) - 新增 `aggregateFunctions` 参数(`CountSqlParser`), 允许手动添加聚合函数(影响行数),所以以聚合函数开头的函数,在进行 count 转换时,会套一层。其他函数和列会被替换为 count(0),其中count列可以自己配置。 增加 `aggregateFunctions` 参数后,和原先最大的区别是,如果存在 `select ifnull(xxx, yy) from table ...`,原先的 count 查询是 `select count(0) from (select ifnull(xxx, yy) from table ...) temp_count`,现在会区别聚合函数,如果不是聚合函数,就会变成 `select count(0) from table ...`。 默认包含的聚合函数前缀如下: ```java /** * 聚合函数,以下列函数开头的都认为是聚合函数 */ private static final Set AGGREGATE_FUNCTIONS = new HashSet(Arrays.asList( ("APPROX_COUNT_DISTINCT," + "ARRAY_AGG," + "AVG," + "BIT_" + //"BIT_AND," + //"BIT_OR," + //"BIT_XOR," + "BOOL_," + //"BOOL_AND," + //"BOOL_OR," + "CHECKSUM_AGG," + "COLLECT," + "CORR," + //"CORR_," + //"CORRELATION," + "COUNT," + //"COUNT_BIG," + "COVAR," + //"COVAR_POP," + //"COVAR_SAMP," + //"COVARIANCE," + //"COVARIANCE_SAMP," + "CUME_DIST," + "DENSE_RANK," + "EVERY," + "FIRST," + "GROUP," + //"GROUP_CONCAT," + //"GROUP_ID," + //"GROUPING," + //"GROUPING," + //"GROUPING_ID," + "JSON_," + //"JSON_AGG," + //"JSON_ARRAYAGG," + //"JSON_OBJECT_AGG," + //"JSON_OBJECTAGG," + //"JSONB_AGG," + //"JSONB_OBJECT_AGG," + "LAST," + "LISTAGG," + "MAX," + "MEDIAN," + "MIN," + "PERCENT_," + //"PERCENT_RANK," + //"PERCENTILE_CONT," + //"PERCENTILE_DISC," + "RANK," + "REGR_," + "SELECTIVITY," + "STATS_," + //"STATS_BINOMIAL_TEST," + //"STATS_CROSSTAB," + //"STATS_F_TEST," + //"STATS_KS_TEST," + //"STATS_MODE," + //"STATS_MW_TEST," + //"STATS_ONE_WAY_ANOVA," + //"STATS_T_TEST_*," + //"STATS_WSR_TEST," + "STD," + //"STDDEV," + //"STDDEV_POP," + //"STDDEV_SAMP," + //"STDDEV_SAMP," + //"STDEV," + //"STDEVP," + "STRING_AGG," + "SUM," + "SYS_OP_ZONE_ID," + "SYS_XMLAGG," + "VAR," + //"VAR_POP," + //"VAR_SAMP," + //"VARIANCE," + //"VARIANCE_SAMP," + //"VARP," + "XMLAGG").split(","))); ``` ### 5.1.4 - 2018-04-22 - 默认增加达梦数据库(dm),可以自动根据 jdbcurl 使用Oracle方式进行分页。如果想换 SqlServer 可以参考 5.1.3 更新日志中的 `dialectAlias` 参数。 ### 5.1.3 - 2018-04-07 - `Page` 的 `toString` 方法增加 `super.toString()`。最终输出形式如 `Page{属性}[集合]`。 - 增加 `defaultCount` 参数,用于控制默认不带 count 查询的方法中,是否执行 count 查询,默认 true 会执行 count 查询,这是一个全局生效的参数,多数据源时也是统一的行为。 - 增加 `dialectAlias` 参数,允许配置自定义实现的 别名,可以用于根据 JDBCURL 自动获取对应实现,允许通过此种方式覆盖已有的实现,配置示例如(多个时分号隔开): ```xml ``` - 增加 `PageSerializable`,简化版的 `PageInfo` 类,不需要那么多信息时,推荐使用或者参考这个类实现。 ### 5.1.2 - 2017-09-18 - 解决单独使用 `PageHelper.orderBy` 方法时的问题 #110; ### 5.1.1 - 2017-08-30 - 此次更新解决的问题只和 SqlServer 2005,2008 有关 - 解决 `RegexWithNolockReplaceSql` 中正则 `w?` 错误的问题,应该是 `w+`。 - 解决 `SqlServerDialect` 中没有初始化默认 `SimpleWithNolockReplaceSql` 的错误。 - `SqlServerRowBoundsDialect` 增加对 `replaceSql` 参数的支持。 ### 5.1.0 - 2017-08-28 - 增加 4.x 以前版本包含的排序功能,用法一致(PageHelper增加了几个排序相关的方法)。 - 分页 SQL 转换为预编译 SQL。 - 增加 `ReplaceSql` 接口用于处理 sqlServer 的 `with(nolock)` 问题,增加了针对性的 `replaceSql` 参数,可选值为 `simple` 和 `regex`,或者是实现了ReplaceSql接口的全限定类名。默认值为 `simple`,仍然使用原来的方式处理,新的 `regex` 会将如 `table with(nolock)` 处理为 `table_PAGEWITHNOLOCK`。 - `PageRowBounds` 增加 `count` 属性,可以控制是否进行 `count` 查询。 ### 5.1.0-beta2 - 2017-08-23 - 增加 `ReplaceSql` 接口用于处理 sqlServer 的 `with(nolock)` 问题,增加了针对性的 `replaceSql` 参数,可选值为 `simple` 和 `regex`,或者是实现了ReplaceSql接口的全限定类名。默认值为 `simple`,仍然使用原来的方式处理,新的 `regex` 会将如 `table with(nolock)` 处理为 `table_PAGEWITHNOLOCK`。 ### 5.1.0-beta - 2017-08-22 - 增加 4.x 以前版本包含的排序功能,用法一致(PageHelper增加了几个排序相关的方法)。 - 分页 SQL 转换为预编译 SQL。 ### 5.0.4 - 2017-08-01 - 增加对 `Phoenix` 数据库的简单配置支持,配置 `helperDialect=phoenix` 即可,也可以自动识别 `Phoenix` 数据库的 jdbc url。 - count 查询的缓存 `msCountMap` key 改为 `String` 类型,key 为 count 查询的 `MappedStatement` 的 id。 - 增加 `countSuffix` count 查询后缀配置参数,该参数是针对 `PageInterceptor` 配置的,默认值为 `_COUNT`。 - 增加手写 count 查询支持,详情看下面介绍。 #### 增加手写 count 查询支持 增加 `countSuffix` count 查询后缀配置参数,该参数是针对 `PageInterceptor` 配置的,默认值为 `_COUNT`。 分页插件会优先通过当前查询的 msId + `countSuffix` 查找手写的分页查询。 如果存在就使用手写的 count 查询,如果不存在,仍然使用之前的方式自动创建 count 查询。 例如,如果存在下面两个查询: ```xml ``` 上面的 `countSuffix` 使用的默认值 `_COUNT`,分页插件会自动获取到 `selectLeftjoin_COUNT` 查询,这个查询需要自己保证结果数正确。 返回值的类型必须是`resultType="Long"`,入参使用的和 `selectLeftjoin` 查询相同的参数,所以在 SQL 中要按照 `selectLeftjoin` 的入参来使用。 因为 `selectLeftjoin_COUNT` 方法是自动调用的,所以不需要在接口提供相应的方法,如果需要单独调用,也可以提供。 上面方法执行输出的部分日志如下: ``` DEBUG [main] - ==> Preparing: select count(distinct a.id) from user a left join user b on a.id = b.id DEBUG [main] - ==> Parameters: TRACE [main] - <== Columns: C1 TRACE [main] - <== Row: 183 DEBUG [main] - <== Total: 1 DEBUG [main] - Cache Hit Ratio [com.github.pagehelper.mapper.CountryMapper]: 0.0 DEBUG [main] - ==> Preparing: select a.id,b.name,a.py from user a left join user b on a.id = b.id order by a.id LIMIT 10 DEBUG [main] - ==> Parameters: TRACE [main] - <== Columns: ID, COUNTRYNAME, COUNTRYCODE TRACE [main] - <== Row: 1, Angola, AO TRACE [main] - <== Row: 2, Afghanistan, AF TRACE [main] - <== Row: 3, Albania, AL ``` ### 5.0.3 -2017-06-20 - 解决`supportMethodsArguments`参数不起作用的问题,由于之前默认为`false`,不起作用后效果为`true`,建议升级到最新版本。 ### 5.0.2 - 2017-05-30 - `Page` 继承 `Closeable` 接口,在 JDK7+中可以使用 `try()`方式调用,自动调用`PageHelper.clearPage();`[#58](https://github.com/pagehelper/Mybatis-PageHelper/issues/58)。 - 解决:DB2分页时必须要指定子查询的别名,不然会发生异常 [#52](https://github.com/pagehelper/Mybatis-PageHelper/issues/52) - 解决:分页取数据时,如果数据一条都没有返回, pageInfo.isIsLastPage(); 返回false [#50](https://github.com/pagehelper/Mybatis-PageHelper/issues/50) ### 5.0.1 - 2017-04-23 - 增加新的参数 `countColumn` 用于配置自动 count 查询时的查询列,默认值`0`,也就是 `count(0)` - `Page` 对象也新增了 `countColumn` 参数,可以针对具体查询进行配置 - 针对文档显示问题进行修改,by liumian* [PR #30](https://github.com/pagehelper/Mybatis-PageHelper/pull/30) - 解决 sqlserver2012 分页错误的问题 [42](https://github.com/pagehelper/Mybatis-PageHelper/issues/42) ### 5.0.0 - 2017-01-02 - 使用 [QueryInterceptor 规范](https://github.com/pagehelper/Mybatis-PageHelper/blob/master/src/main/java/com/github/pagehelper/QueryInterceptor.java) 处理分页逻辑 - 新的分页插件拦截器为 `com.github.pagehelper.PageInterceptor` - 新的 `PageHelper` 是一个特殊的 `Dialect` 实现类,以更友好的方式实现了以前的功能 - 新的分页插件仅有 `dialect` 一个参数,默认的 `dialect` 实现类为 `PageHelper` - `PageHelper` 仍然支持以前提供的参数,在最新的使用文档中已经全部更新 - `PageHelper` 的 `helperDialect` 参数和以前的 `dialect` 功能一样,具体可以看文档的参数说明 - 增加了基于纯 `RowBounds` 和 `PageRowBounds` 的分页实现,在 `com.github.pagehelper.dialect.rowbounds` 包中,这是用于作为 `dialect` 参数示例的实现,后面会补充更详细的文档 - 去掉了不适合出现在分页插件中的 orderby 功能,以后会提供单独的排序插件 - 去掉了 `PageHelper` 中不常用的方法 - 新的文档,更新历来更新日志中提到的重要内容,提供英文版本文档 - 解决 bug [#149](http://git.oschina.net/free/Mybatis_PageHelper/issues/149) - 将 Db2RowDialect 改为 Db2RowBoundsDialect - 所有分页插件抛出的异常改为 PageException ### 4.2.1 - 2016-12-11 - 解决`SimpleCache`类遗留问题导致的错误 [#143](http://git.oschina.net/free/Mybatis_PageHelper/issues/143) fix by [dhhua](https://github.com/dhhua) ### 4.2.0 - 2016-12-09 - 使用新的方式进行分页,4.2版本是从5.0版本分离出来的一个特殊版本,这个版本兼容4.x的所有功能,5.0版本时为了简化分页逻辑,会去掉部分功能,所以4.2是4.x的最后一个版本。 - 支持 MyBatis 3.1.0+ 版本 - 增加对 Derby 数据库的支持 - 对除 informix 外的全部数据库进行测试,全部通过 - PageHelper增加手动清除方法`clearPage()` - 解决 SqlServer 多个`with(nolock)`时出错的问题 - 对CountMappedStatement 进行缓存,配置方式见BaseSqlUtil 319行 - 由于SqlServer的sql处理特殊,因此增加了两个SQL缓存,具体配置参考SqlServerDialect类 - 添加 sqlserver 别名进行排序功能,在解析sql时,会自动将使用的别名转换成列名 by panmingzhi - 新增`sqlCacheClass`参数,该参数可选,可以设置sql缓存实现类,默认为`SimpleCache`,当项目包含guava时,使用`GuavaCache`,也可以通过参数`sqlCacheClass`指定自己的实现类,有关详情看`com.github.pagehelper.cache`包。 - 解决#135,增加/*keep orderby*/注解,SQL中包含该注释时,count查询时不会移出order by - sqlserver没有orderby时,使用`order by rand()` #82 #118 ### 4.1.6 - 2016-06-05 - 通过间接处理字符串解决SqlServer中不支持`with(nolock)`的问题#86,详情可以看`SqlServerParser`和`SqlServer2012Dialect` ### 4.1.5 - 2016-05-29 - 更新`PageProviderSqlSource`,支持3.4.0版本的`Provider`注解方式的分页#102 - 解决`SqlUtil`未初始化`PARAMS`属性导致的错误 ### 4.1.4 - 2016-05-12 - 解决`closeConn`未设置时,默认值被覆盖变成`false`的问题#97 - `closeConn`不只对动态数据源有效,当没有设置`dialect`属性自动获取数据库类型的时候同样有效 - 解决关闭tomcat的时候提示线程安全问题#98,这个问题不会导致内存溢出,已经增加处理 ### 4.1.3 - 2016-03-31 - 解决反射类没有完全捕获异常的问题#94 - 把SqlServer类所有private都改成了protected,方便继承修改#93 ### 4.1.2 - 2016-03-06 - 增加可配参数`closeConn`,当使用动态数据源时,分页插件获取jdbcUrl后,控制是否关闭当前连接,默认`true`关闭 - count查询改为`count(0)`,分库分表情况下的效率可能更高 ### 4.1.1 - 2016-01-05: - 解决动态数据源时获取连接后未关闭的严重bug#80 - 解决动态数据源时SqlSource和parser绑定导致不能切换方言的问题 ### 4.1.0 - 2015-12-30: - 增加`autoRuntimeDialect`参数,允许在运行时根据多数据源自动识别对应方言的分页(暂时不支持自动选择`sqlserver2012`,只能使用`sqlserver`)。 - 去掉了4.0.3版本增加的`returnPageInfo`参数,接口返回值不支持`PageInfo`类型,可以使用下面`ISelect`中演示的方法获取 - 增加对`SqlServer2012`的支持,需要手动指定`dialect=sqlserver2012`,否则会使用2005的方式进行分页 - jsqlparser升级到0.9.4版本,使用jar包时必须用最新的0.9.4版本,使用Maven会自动依赖0.9.4 - 增加`ISelect`接口,方便调用,使用方法可以参考`src/test/java/com.github.pagehelper.test.basic.TestISelect`测试。 ### 使用该接口可以参考如下用法(返回值为`Page`或`PageInfo`): ```java //jdk6,7用法,创建接口 Page page = PageHelper.startPage(1, 10).setOrderBy("id desc").doSelectPage(new ISelect() { @Override public void doSelect() { userMapper.selectGroupBy(); } }); //jdk8 lambda用法 Page page = PageHelper.startPage(1, 10).setOrderBy("id desc").doSelectPage(()-> userMapper.selectGroupBy()); //为了说明可以链式使用,上面是单独setOrderBy("id desc"),也可以直接如下 Page page = PageHelper.startPage(1, 10, "id desc").doSelectPage(()-> userMapper.selectGroupBy()); //也可以直接返回PageInfo,注意doSelectPageInfo方法和doSelectPage pageInfo = PageHelper.startPage(1, 10).setOrderBy("id desc").doSelectPageInfo(new ISelect() { @Override public void doSelect() { userMapper.selectGroupBy(); } }); //对应的lambda用法 pageInfo = PageHelper.startPage(1, 10).setOrderBy("id desc").doSelectPageInfo(() -> userMapper.selectGroupBy()); //count查询,返回一个查询语句的count数 long total = PageHelper.count(new ISelect() { @Override public void doSelect() { userMapper.selectLike(user); } }); //lambda total = PageHelper.count(()->userMapper.selectLike(user)); ``` ### 4.0.3 - 2015-11-09: - `PageHelper`新增3个`offsetPage`方法,参数主要是`offset`和`limit`,允许不规则分页 - 新增两个可配参数`supportMethodsArguments`和`returnPageInfo`(该参数在4.1.0版本去掉),具体含义和用法请看[如何使用分页插件](https://github.com/pagehelper/Mybatis-PageHelper/blob/master/wikis/zh/HowToUse.md)中的参数介绍 ### 4.0.2 - 2015-11-02 - 简化`Page`类,包含排序条件`orderBy` - `dialect`参数是数据库名称时不区分大小写 - `dialect`参数可以设置为实现`com.github.pagehelper.parser.Parser`接口的实现类全限定名称 - 增加对`h2`数据库的支持 - 将`OrderByHelper`(排序插件)融合到`PageHelper`中,移除`OrderByHelper` - 该版本调整比较大,但对开发人员影响较小,为以后扩展和完善提供方便 ### 4.0.1 -2015-09-10 - 解决[#60 -使用RPC时,因Page类引用了RowBounds,导致反序列化失败](http://git.oschina.net/free/Mybatis_PageHelper/issues/60) by [马金凯](http://git.oschina.net/mxb) - 这个改动主要是去掉了`Page`构造方法中的`RowBounds`,用`int[]`数组替换了`RowBounds` ### 4.0.0 - 2015-07-13 - 配置属性`dialect`不在强制要求,可以不写,分页插件会自动判断 - 解决从request中获取分页参数时的错误,感谢探路者☆ - `PageInfo`增加空构造方法,所有属性增加`setter`方法 - 增加对排序的支持 - 可以单独使用`PageHelper.orderBy(String orderBy)`对查询语句增加排序,也可以配合`startPage`的其他方法使用 - 可以使用`PageHelper.startPage(int start,int size,String orderBy)`对分页查询进行排序 - 修改分页查询的处理逻辑,主要是将原`sqlSource`包装成可以分页和排序的`sqlSource` ### 3.7.5 - 2015-06-12 - 增加对MyBatis3.2.0以上版本的校验,如果是不是3.2.0以上版本,会抛出异常提示 - 解决3.7.1更新中实际没有解决的入参为不可变`Map`类型时的错误 ### 3.7.4 - 2015-05-26 - 为了支持`3.3.0`去掉了分页插件自带的`SytemObjectMetaObject`类(该类在早期版本为了支持3.2.0以前的MyBatis) - 最新支持MyBatis - 3.2.0到最新3.3.0版本 ### 3.7.3 - 2015-05-22 - `Page`继承的`ArrayList`,会根据`pageSize`初始化大小,这就导致当`pageSize`过大(如`Integer.MAX_VALUE`),实际数据量很小时的内存溢出,此处改为初始化大小为0的`List`。 - 当想查询某页后面的全部数据时,可以使用`PageHelper.startPage(pageNum, Integer.MAX_VALUE)`进行分页,`RowBounds(offset, Integer.MAX_VALUE)`一样。 - 针对`PageHelper.startPage(1, Integer.MAX_VALUE)`优化,会取消分页,直接查询全部数据(能起到`pageSizeZero`参数所起的作用)。 - 针对`RowBounds(0, Integer.MAX_VALUE)`优化,会取消分页,直接查询全部数据(能起到`pageSizeZero`参数所起的作用)。 ### 3.7.2 - 2015-05-13 - jsqlparser解析sql会抛出Error异常,由于只捕获Exception,所以导致部分解析失败的sql无法使用嵌套方式处理,所以修改为捕获`Throwable`。 ### 3.7.1 - 2015-05-05 - 增加`Infomix`数据库支持,设置`dialect`值为`infomix`即可 - 解决入参为不可变`Map`类型时的错误 ### 3.7.0 - 2015-04-21 - 由于`orderby`参数经常被错误认为的使用,因此该版本全面移除了`orderby` - `Page`移除`orderby`属性 - `PageHelper`的`startPage`方法中,移除包含`orderby`参数的方法,sqlserver相关包含该参数的全部移除 - 对SqlServer进行分页查询时,请在sql中包含order by语句,否则会抛出异常 - 当`offsetAsPageNum=false`的时候,由于PageNum问题,`RowBounds`查询的时候`reasonable`会强制为false,已解决 - 少数情况下的select中包含单个函数查询时,会使用嵌套的count查询 ### 3.6.4 - 2015-04-05 - 重构,将原来的内部类全部独立出来,尤其是`Parser`接口以及全部实现。 现在可以直接使用`Parser`,使用方法如下: ```java String originalSql = "Select * from user o where id > 10 order by id desc "; Parser parser = AbstractParser.newParser("mysql"); //获取count查询sql String countSql = parser.getCountSql(originalSql); //获取分页sql,这种方式不适合sqlserver数据库 String pageSql = parser.getPageSql(originalSql); //sqlserver用下面的方法 SqlServer sqlServer = new SqlServer(); pageSql = sqlServer.convertToPageSql(originalSql, 1, 10); ``` ### 3.6.3 - 2015-03-10 - 解决了一个潜在的bug,对[通用Mapper](http://git.oschina.net/free/Mapper)中的`SqlMapper`进行分页时,需要使用这个版本 ### 3.6.2 - 2015-03-09 - 本次更新只是增加了一个异常提示,当错误的配置了多个分页插件时,会有更友好的错误提示: >分页插件配置错误:请不要在系统中配置多个分页插件(使用Spring时,mybatis-config.xml和Spring配置方式,请选择其中一种,不要同时配置多个分页插件)! ### 3.6.1 - 2015-02-28 - 解决select distinct导致count查询结果不正确的bug#35 - 完善测试 ### 3.6.0 - 2015-02-03 - 支持db2数据库 - 支持sqlserver(2005+)数据库 - sqlserver注意事项: - 请先保证你的SQL可以执行 - sql中最好直接包含order by,可以自动从sql提取 - 如果没有order by,可以通过入参提供,但是需要自己保证正确(3.7.0版本以后,移除了该参数,请在sql中包含order by) - 如果sql有order by,可以通过orderby参数覆盖sql中的order by - order by的列名不能使用别名(`UNION,INTERSECT,MINUS,EXCEPT`等复杂sql不受限制,具体可以自己尝试) - 表和列使用别名的时候不要使用单引号(') - 简单修改结构 - `startPage`方法返回值从`void`改为`Page`,获取`Page`后可以修改参数值 - `Page`增加一个针对sqlserver的属性`orderBy`(3.7.0版本以后,移除了该属性),用法看上面的注意事项 - `Page`增加了一个链式赋值的方法,可以像下面这样使用: `PageHelper.startPage(1,10).count(false).reasonable(true).pageSizeZero(false)` - `PageHelper`增加了`startPage(int pageNum, int pageSize,String orderBy)`方法(3.7.0版本以后,移除了该方法),针对sqlserver ### 3.5.1 - 2015-01-20 - 解决[bug#25](http://git.oschina.net/free/Mybatis_PageHelper/issues/25),当参数是null并且是动态查询时,由于加入分页参数,导致参数不在是null,因而会导致部分判断出错,导致异常。 - 上面这个bug会影响使用了动态标签并且允许入参为null的所有查询,虽然并不常见,但是建议各位使用最新版本 ### 3.5.0 - 2015-01-11 - 增加更丰富的调用方法[#23](http://git.oschina.net/free/Mybatis_PageHelper/issues/23) - `startPage(int pageNum, int pageSize)` - `startPage(int pageNum, int pageSize, boolean count)` - +`startPage(int pageNum, int pageSize, boolean count, Boolean reasonable)` - +`startPage(int pageNum, int pageSize, boolean count, Boolean reasonable, Boolean pageSizeZero)` - +`startPage(Object params)`注:只能是`Map`或`ServletRequest`类型 参数中的`reasonable`、`pageSizeZero`都可以覆盖默认配置,如果传`null`会用默认配置。 - 为了支持`startPage(Object params)`方法,增加了一个`params`参数来配置参数映射,用于从`Map`或`ServletRequest`中取值,详细内容看文档下面的具体介绍。 - 解决一个``标签使用对象内部属性循环时的bug[#24](http://git.oschina.net/free/Mybatis_PageHelper/issues/24) ### 3.4.2 - 2014-12-27 - `PageInfo`中的`judgePageBoudary`方法修改: ```java isLastPage = pageNum == pages && pageNum != 1; //改为 isLastPage = pageNum == pages; ``` ### 3.4.1 - 2014-12-24 - 重大bug修复,`SqlParser`解析sql失败的时候返回了不带`count(*)`的sql,导致查询失败。 - 产生原因,由于`SqlParser`在系统中出现的位置修改后,导致这里出现错误。 - 强烈推荐各位更新到最新版本。 ### v3.4.0 - 2014-12-18 - 增加了对`@SelectProvider`注解方法的支持,不使用这种方式的不影响 - 对基本逻辑进行修改,减少反射调用和获取`BoundSql`次数 ### v3.3.2 - 2014-12-10 - `PageInfo` 增加序列化。 ### v3.3.1bug修复 - 2014-12-07 - 动态sql时,判断条件不会出现在ParameterMappings中,会导致获取不到属性。通常是因为判断条件中的属性没有出现在`#{}`中。 ### v3.3.0 1. 对`MappedStatement`对象进行缓存,包括count查询的`MappedStatement`以及分页查询的`MappedStatement`,分页查询改为预编译查询。 2. 独立的`SqlUtil`类,由于原来的`PageHelper`太复杂,因此将拦截器外的其他代码独立到`SqlUtil`中,方便查看代码和维护。`SqlUtil`中增加`Parser`接口,提供一个抽象的`SimpleParser`实现,不同数据库的分页代码通过继承`SimpleParser`实现。 3. 特殊的`Parser`实现类`SqlParser`类,这是一个独立的java类,主要提供了更高性能的count查询sql,可以根据sql自动改为`count(*)`查询,自动去除不需要的`order by` 语句,如果需要使用该类,只要把该类放到`SqlUtil`类相同的包下即可,同时需要引入Jar包`jsqlparser-0.9.1.jar`。 4. 增强的`PageInfo`类,`PageInfo`类包含了分页几乎所有需要用到的属性值,减少了对分页逻辑的过多投入。 4. 分页合理化,自动处理pageNum的异常情况。例如当pageNum<=0时,会设置pageNum=1,然后查询第一页。当pageNum>pages(总页数)时,自动将pageNum=pages,查询最后一页。 5. 增加对`PostgreSQL`,`MariaDB`,`SQLite`支持。其中`MariaDB`,`SQLite`和`Mysql`分页一样。 ### v3.2.3 1. 解决`mysql`带有`for update`时分页错误的问题。 2. 当`pageSize`(或`RowBounds`的`limit`)`<=0` 时不再进行分页查询,只会进行count查询(RowBounds需要配置进行count查询),相当于用分页查询来做count查询了。 3. 增加了`pageSizeZero`参数,当`pageSizeZero=true`时,如果`pageSize=0`(或`RowBounds.limit` =0),就会查询全部的结果。这个参数对于那些在特殊情况下要查询全部结果的人有用。配置该参数后会与上面第二条冲突,解决方法就是如果只想查询count,就设置`pageSize<0`(如 `-1` ),只要不等于0(或者不配置pageSizeZero)就不会出现全部查询的情况。 4. 这个版本没有包含count查询时自动去除`order by`的功能,这个功能将会添加到3.3.0版本中。 5. 为了便于本项目的统一管理和发布,本项目会和github上面同步,项目会改为Maven管理的结构。 ### v3.2.2 1. 简单重构优化代码。 2. 新增`PageInfo`包装类,对分页结果Page进行封装,方便EL使用。 3. 将`SystemMetaObject`类的`fromObject`方法内置到分页插件中,方便低版本的Mybatis使用该插件。 ### v3.2.1 1. 新增`offsetAsPageNum`参数,用来控制`RowBounds`中的`offset`是否作为`pageNum`使用,`pageNum`和`startPage`中的含义相同,`pageNum`是页码。该参数默认为`false`,使用默认值时,不需要配置该参数。 2. 新增`rowBoundsWithCount`参数,用来控制使用`RowBounds`时是否执行`count`查询。该参数默认为`false`,使用默认值时,不需要配置该参数。 ### v3.2.0 1. 增加了对`Hsqldb`的支持,主要目的是为了方便测试使用`Hsqldb` 2. 增加了该项目的一个测试项目[Mybatis-Sample](http://git.oschina.net/free/Mybatis-Sample),测试项目数据库使用`Hsqldb` 3. 增加MIT协议 ### v3.1.2 1. 解决count sql在`oracle`中的错误 ### v3.1.1 1. 统一返回值为`Page`(可以直接按`List`使用),方便在页面使用EL表达式,如`${page.pageNum}`,`${page.total}` ### v3.1.0 1. 解决了`RowBounds`分页的严重BUG,原先会在物理分页基础上进行内存分页导致严重错误,已修复 2. 增加对MySql的支持,该支持由[鲁家宁](http://my.oschina.net/lujianing)增加。 ### v3.0 1. 现在支持两种形式的分页,使用`PageHelper.startPage`方法或者使用`RowBounds`参数 2. `PageHelper.startPage`方法修改,原先的`startPage(int pageNum, int pageSize)` 默认求count,新增的`startPage(int pageNum, int pageSize, boolean count)`设置`count=false`可以不执行count查询 3. 移除`endPage`方法,现在本地变量`localPage`改为取出后清空本地变量。 4. 修改`Page`类,继承`ArrayList` 5. 关于两种形式的调用,请看示例代码 ### v2.1 1. 解决并发异常 2. 分页sql改为直接拼sql ### v2.0 1. 支持Mybatis缓存,count和分页同时支持(二者同步) 2. 修改拦截器签名,拦截`Executor` 3. 将`Page`类移到外面,方便调用 ### v1.0 1. 支持``等标签的分页查询 2. 提供便捷的使用方式 ================================================ FILE: wikis/zh/HowToUse.md ================================================ ## 使用方法 ### 1. 引入分页插件 #### 1). 使用 Maven 在 pom.xml 中添加如下依赖: ```xml com.github.pagehelper pagehelper 最新版本 ``` #### 2). 使用 Gradle 在 `build.gradle` 中添加: ```groovy dependencies { compile("com.github.pagehelper:pagehelper:最新版本") } ``` #### 3). 使用 Spring Boot 时 Maven: ```xml com.github.pagehelper pagehelper-spring-boot-starter 最新版本 ``` Gradle: ```groovy dependencies { compile("com.github.pagehelper:pagehelper-spring-boot-starter:最新版本") } ``` ### 2. 配置拦截器插件 特别注意,新版拦截器是 `com.github.pagehelper.PageInterceptor`。 `com.github.pagehelper.PageHelper` 现在是一个特殊的 `dialect` 实现类,是分页插件的默认实现类,提供了和以前相同的用法。 #### 1). 在 MyBatis 配置 xml 中配置拦截器插件 ```xml ``` #### 2). 在 Spring 配置文件中配置拦截器插件 使用 spring 的 XML 配置方式,可以使用 `plugins` 属性像下面这样配置: ```xml params=value1 ``` #### 3). 在 Spring Boot 中配置 Spring Boot 引入 starter 后自动生效,对分页插件进行配置时,在 Spring Boot 对应的配置文件 `application.[properties|yaml]` 中配置: properties: ```properties pagehelper.propertyName=propertyValue pagehelper.reasonable=false pagehelper.defaultCount=true ``` yaml: ```yaml pagehelper: propertyName: propertyValue reasonable: false defaultCount: true # 分页插件默认参数支持 default-count 形式,自定义扩展的参数,必须大小写一致 ``` > 分页插件默认参数支持 default-count 形式,自定义扩展的参数,必须大小写一致。 > > 支持的默认参数参考: [PageHelperStandardProperties.java](https://github.com/pagehelper/pagehelper-spring-boot/blob/master/pagehelper-spring-boot-autoconfigure/src/main/java/com/github/pagehelper/autoconfigure/PageHelperStandardProperties.java) #### 4). 分页插件横幅banner设置 为了避免多次配置分页插件导致的错误,配置分页插件后,启动时会输出 banner。 ``` DEBUG [main] - ,------. ,--. ,--. ,--. | .--. ' ,--,--. ,---. ,---. | '--' | ,---. | | ,---. ,---. ,--.--. | '--' | ' ,-. | | .-. | | .-. : | .--. | | .-. : | | | .-. | | .-. : | .--' | | --' \ '-' | ' '-' ' \ --. | | | | \ --. | | | '-' ' \ --. | | `--' `--`--' .`- / `----' `--' `--' `----' `--' | |-' `----' `--' `---' `--' is intercepting. ``` 如果在项目启动时输出了多次 banner,就是配置了多次分页插件,根据日志输出的位置排查系统通过哪些方式配置了分页插件。 如果不想在启动时输出 banner,可以通过系统变量或环境变量关闭。 - 系统变量:`-Dpagehelper.banner=false` - 环境变量:`PAGEHELPER_BANNER=false` #### 5). 分页插件参数介绍 分页插件提供了多个可选参数,这些参数使用时,按照上面配置方式中的示例配置即可。 **分页插件可选参数如下:** 1. `debug`: 调试参数,默认 `false` 关闭,设置为 `true` 启用后,可以排查系统中存在的**不安全调用**,[#查看如何安全调用](#3-pagehelper-安全调用)。 通过 `PageHelper.startPage` 等静态方法调用设置分页参数时,会记录当前执行的方法堆栈信息,当执行 MyBatis 的查询方法时,会使用设置好的分页参数, 此时会输出设置时的方法堆栈,通过查看堆栈,如果和当前执行的方法不一致,那么堆栈中对应的调用就是**不安全调用**,需要根据 [#安全调用](#3-pagehelper-安全调用) 中的方式调整。输出的堆栈示例如下: ``` 00:19:08.915 [main] DEBUG c.github.pagehelper.PageInterceptor - java.lang.Exception: 设置分页参数时的堆栈信息 at com.github.pagehelper.util.StackTraceUtil.current(StackTraceUtil.java:12) at com.github.pagehelper.Page.(Page.java:111) at com.github.pagehelper.Page.(Page.java:126) at com.github.pagehelper.page.PageMethod.startPage(PageMethod.java:139) at com.github.pagehelper.page.PageMethod.startPage(PageMethod.java:113) at com.github.pagehelper.page.PageMethod.startPage(PageMethod.java:102) at com.github.pagehelper.test.basic.PageHelperTest.testNamespaceWithStartPage(PageHelperTest.java:118) ...省略 00:19:09.069 [main] DEBUG c.g.pagehelper.mapper.UserMapper - Cache Hit Ratio [com.github.pagehelper.mapper.UserMapper]: 0.0 00:19:09.077 [main] DEBUG o.a.i.t.jdbc.JdbcTransaction - Opening JDBC Connection 00:19:09.078 [main] DEBUG o.a.i.t.jdbc.JdbcTransaction - Setting autocommit to false on JDBC Connection [org.hsqldb.jdbc.JDBCConnection@6da21078] 00:19:09.087 [main] DEBUG c.g.p.m.UserMapper.selectAll_COUNT - ==> Preparing: SELECT count(1) FROM user 00:19:09.121 [main] DEBUG c.g.p.m.UserMapper.selectAll_COUNT - ==> Parameters: 00:19:09.131 [main] TRACE c.g.p.m.UserMapper.selectAll_COUNT - <== Columns: C1 00:19:09.131 [main] TRACE c.g.p.m.UserMapper.selectAll_COUNT - <== Row: 183 00:19:09.147 [main] DEBUG c.g.p.m.UserMapper.selectAll_COUNT - <== Total: 1 ``` 2. `dialect`:默认情况下会使用 PageHelper 方式进行分页,如果想要实现自己的分页逻辑,可以实现 `Dialect`(`com.github.pagehelper.Dialect`) 接口,然后配置该属性为实现类的全限定名称。 3. `countSuffix`:根据查询创建或者查找对应的 count 查询时,追加的 msId 后缀,默认 `_COUNT`。 4. `countMsIdGen`(5.3.2+):count 方法的 msId 生成方式,默认是 查询的 msId + countSuffix,想要自己定义时,可以实现 `com.github.pagehelper.CountMsIdGen` 接口,将该参数配置为实现的全限定类名即可。 **一个常见的用途:** 在有Example查询的情况,`selectByExample` 可以使用对应的 `selectCountByExample` 方法进行 count 查询。 5. `msCountCache`:自动创建查询的 count 查询方法时,创建的 count `MappedStatement` 会进行缓存,默认会优先查找 `com.google.common.cache.Cache` 的实现,如果项目没有 guava 依赖就会使用 mybatis 内置的 `CacheBuilder` 创建。想要对缓存进行细粒度的配置请参考源码: `com.github.pagehelper.cache.CacheFactory` ,两种默认方案提供了多个属性进行配置,也可以按照这里要求自己扩展实现。 **下面几个参数都是针对默认 dialect 情况下的参数。使用自定义 dialect 实现时,下面的参数没有任何作用。** 1. `helperDialect`:分页插件会自动检测当前的数据库链接,自动选择合适的分页方式。 你可以配置`helperDialect`属性来指定分页插件使用哪种方言。配置时,可以使用下面的缩写值: `oracle`,`mysql`,`mariadb`,`sqlite`,`hsqldb`,`postgresql`,`db2`,`sqlserver`,`informix`,`h2`,`sqlserver2012`,`derby` (完整内容看 [PageAutoDialect](src/main/java/com/github/pagehelper/page/PageAutoDialect.java)) 特别注意:使用 SqlServer2012 数据库时,需要手动指定为 `sqlserver2012`,否则会使用 SqlServer2005 的方式进行分页,还可以设置 `useSqlserver2012=true` 将2012改为sqlserver的默认方式。 你也可以实现 `AbstractHelperDialect`,然后配置该属性为实现类的全限定名称即可使用自定义的实现方法。 2. `dialectAlias`:允许配置自定义实现的 别名,可以用于根据 JDBCURL 自动获取对应实现,允许通过此种方式覆盖已有的实现,配置示例如(多个时分号隔开): ```xml ``` 当你使用的 jdbcurl 不在 [PageAutoDialect](src/main/java/com/github/pagehelper/page/PageAutoDialect.java) 默认提供范围时,可以通过改参数实现自动识别。 3. `useSqlserver2012`(sqlserver):使用 SqlServer2012 数据库时,需要手动指定为 `sqlserver2012`,否则会使用 SqlServer2005 的方式进行分页,还可以设置 `useSqlserver2012=true`将2012改为sqlserver的默认方式。 4. `defaultCount`:用于控制默认不带 count 查询的方法中,是否执行 count 查询,默认 `true` 会执行 count 查询,这是一个全局生效的参数,多数据源时也是统一的行为。 5. `countColumn`:用于配置自动 count 查询时的查询列,默认值`0`,也就是 `count(0)`,`Page` 对象也新增了 `countColumn` 参数,可以针对具体查询进行配置。 6. `offsetAsPageNum`:默认值为 `false`,该参数对使用 `RowBounds` 作为分页参数时有效。 当该参数设置为 `true` 时,会将 `RowBounds` 中的 `offset` 参数当成 `pageNum` 使用,可以用页码和页面大小两个参数进行分页。 7. `rowBoundsWithCount`:默认值为`false`,该参数对使用 `RowBounds` 作为分页参数时有效。 当该参数设置为`true`时,使用 `RowBounds` 分页会进行 count 查询。 8. `pageSizeZero`:默认值为 `false`,当该参数设置为 `true` 时,如果 `pageSize=0` 或者 `RowBounds.limit = 0` 就会查询出全部的结果(相当于没有执行分页查询,但是返回结果仍然是 `Page` 类型)。 9. `reasonable`:分页合理化参数,默认值为`false`。当该参数设置为 `true` 时,`pageNum<=0` 时会查询第一页, `pageNum>pages`(超过总数时),会查询最后一页。默认`false` 时,直接根据参数进行查询。 10. `params`:为了支持`startPage(Object params)`方法,增加了该参数来配置参数映射,用于从对象中根据属性名取值, 可以配置 `pageNum,pageSize,count,pageSizeZero,reasonable`,不配置映射的用默认值, 默认值为`pageNum=pageNum;pageSize=pageSize;count=countSql;reasonable=reasonable;pageSizeZero=pageSizeZero`。 11. `supportMethodsArguments`:支持通过 Mapper 接口参数来传递分页参数,默认值`false`,分页插件会从查询方法的参数值中,自动根据上面 `params` 配置的字段中取值,查找到合适的值时就会自动分页。 使用方法可以参考测试代码中的 `com.github.pagehelper.test.basic` 包下的 `ArgumentsMapTest` 和 `ArgumentsObjTest`。 12. `autoRuntimeDialect`:默认值为 `false`。设置为 `true` 时,允许在运行时根据多数据源自动识别对应方言的分页 (不支持自动选择`sqlserver2012`,只能使用`sqlserver`),用法和注意事项参考下面的**场景五**。 13. `closeConn`:默认值为 `true`。当使用运行时动态数据源或没有设置 `helperDialect` 属性自动获取数据库类型时,会自动获取一个数据库连接, 通过该属性来设置是否关闭获取的这个连接,默认`true`关闭,设置为 `false` 后,不会关闭获取的连接,这个参数的设置要根据自己选择的数据源来决定。 14. `aggregateFunctions`(5.1.5+):默认为所有常见数据库的聚合函数,允许手动添加聚合函数(影响行数),所有以聚合函数开头的函数,在进行 count 转换时,会套一层。其他函数和列会被替换为 count(0) ,其中count列可以自己配置。 15. `replaceSql`(sqlserver): 可选值为 `regex` 和 `simple`,默认值空时采用 `regex` 方式,也可以自己实现 `com.github.pagehelper.dialect.ReplaceSql` 接口。 16. `sqlCacheClass`(sqlserver): 针对 sqlserver 生成的 count 和 page sql 进行缓存,缓存使用的 `com.github.pagehelper.cache.CacheFactory` ,可选的参数和前面的 `msCountCache` 一样。 17. `autoDialectClass`:增加 `AutoDialect` 接口用于自动获取数据库类型,可以通过 `autoDialectClass` 配置为自己的实现类,默认使用 `DataSourceNegotiationAutoDialect`,优先根据连接池获取。 默认实现中,增加针对 `hikari,druid,tomcat-jdbc,c3p0,dbcp` 类型数据库连接池的特殊处理,直接从配置获取jdbcUrl,当使用其他类型数据源时,仍然使用旧的方式获取连接在读取jdbcUrl。 想要使用和旧版本完全相同方式时,可以配置 `autoDialectClass=old`。当数据库连接池类型非常明确时,建议配置为具体值,例如使用 hikari 时,配置 `autoDialectClass=hikari` ,使用其他连接池时,配置为自己的实现类。 18. `boundSqlInterceptors`:增加分页插件的 `BoundSqlInterceptor` 拦截器,可以在3个阶段对 SQL 进行处理或者简单读取, 增加参数 `boundSqlInterceptors`,可以配置多个实现 `BoundSqlInterceptor` 接口的实现类名, 使用英文逗号隔开。PageHelper调用时,也可以通过类似 `PageHelper.startPage(x,x).boundSqlInterceptor(BoundSqlInterceptor boundSqlInterceptor)`针对本次分页进行设置。 19. `keepOrderBy`:转换count查询时保留查询的 order by 排序。除全局配置外,可以针对单次操作进行设置。 20. `keepSubSelectOrderBy`:转换count查询时保留子查询的 order by 排序。可以避免给所有子查询添加 `/*keep orderby*/`,除全局配置外,可以针对单次操作进行设置。 21. `sqlParser`:配置 JSqlParser 解析器,注意是 `com.github.pagehelper.JSqlParser` 接口,用于支持 sqlserver 等需要额外配置的情况(**6.1.0 移除该参数**)。 **重要提示:** 当 `offsetAsPageNum=false` 的时候,由于 `PageNum` 问题,`RowBounds`查询的时候 `reasonable` 会强制为 `false`。使用 `PageHelper.startPage` 方法不受影响。 #### 6. 如何选择配置这些参数 单独看每个参数的说明可能是一件让人不爽的事情,这里列举一些可能会用到某些参数的情况。 ##### 场景一 如果你仍然在用类似ibatis式的命名空间调用方式,你也许会用到`rowBoundsWithCount`, 分页插件对`RowBounds`支持和 MyBatis 默认的方式是一致,默认情况下不会进行 count 查询,如果你想在分页查询时进行 count 查询, 以及使用更强大的 `PageInfo` 类,你需要设置该参数为 `true`。 **注:** `PageRowBounds` 想要查询总数也需要配置该属性为 `true`。 ##### 场景二 如果你仍然在用类似ibatis式的命名空间调用方式,你觉得 `RowBounds` 中的两个参数 `offset,limit` 不如 `pageNum,pageSize` 容易理解, 你可以使用 `offsetAsPageNum` 参数,将该参数设置为 `true` 后,`offset`会当成 `pageNum` 使用,`limit` 和 `pageSize` 含义相同。 ##### 场景三 如果觉得某个地方使用分页后,你仍然想通过控制参数查询全部的结果,你可以配置 `pageSizeZero` 为 `true`, 配置后,当 `pageSize=0` 或者 `RowBounds.limit = 0` 就会查询出全部的结果。 ##### 场景四 如果你分页插件使用于类似分页查看列表式的数据,如新闻列表,软件列表, 你希望用户输入的页数不在合法范围(第一页到最后一页之外)时能够正确的响应到正确的结果页面, 那么你可以配置 `reasonable` 为 `true`,这时如果 `pageNum<=0` 会查询第一页,如果 `pageNum>总页数` 会查询最后一页。 ##### 场景五 如果你在 Spring 中配置了动态数据源,并且连接不同类型的数据库,这时你可以配置 `autoRuntimeDialect` 为 `true`,这样在使用不同数据源时,会使用匹配的分页进行查询。 这种情况下,你还需要特别注意 `closeConn` 参数,由于获取数据源类型会获取一个数据库连接,所以需要通过这个参数来控制获取连接后,是否关闭该连接。 默认为 `true`,有些数据库连接关闭后就没法进行后续的数据库操作。而有些数据库连接不关闭就会很快由于连接数用完而导致数据库无响应。所以在使用该功能时,特别需要注意你使用的数据源是否需要关闭数据库连接。 当不使用动态数据源而只是自动获取 `helperDialect` 时,数据库连接只会获取一次,所以不需要担心占用的这一个连接是否会导致数据库出错,但是最好也根据数据源的特性选择是否关闭连接。 ### 3. 如何在代码中使用 阅读前请注意看[重要提示](https://github.com/pagehelper/Mybatis-PageHelper/blob/master/wikis/zh/Important.md) 分页插件支持以下几种调用方式: ```java //第一种,RowBounds方式的调用 List list = sqlSession.selectList("x.y.selectIf", null, new RowBounds(0, 10)); //第二种,Mapper接口方式的调用,推荐这种使用方式。 PageHelper.startPage(1, 10); List list = userMapper.selectIf(1); //第三种,Mapper接口方式的调用,推荐这种使用方式。 PageHelper.offsetPage(0, 10); List list = userMapper.selectIf(1); //第四种,参数方法调用 //存在以下 Mapper 接口方法,你不需要在 xml 处理后两个参数 public interface CountryMapper { List selectByPageNumSize( @Param("user") User user, @Param("pageNum") int pageNum, @Param("pageSize") int pageSize); } //配置supportMethodsArguments=true //在代码中直接调用: List list = userMapper.selectByPageNumSize(user, 1, 10); //第五种,参数对象 //如果 pageNum 和 pageSize 存在于 User 对象中,只要参数有值,也会被分页 //有如下 User 对象 public class User { //其他fields //下面两个参数名和 params 配置的名字一致 private Integer pageNum; private Integer pageSize; } //存在以下 Mapper 接口方法,你不需要在 xml 处理后两个参数 public interface CountryMapper { List selectByPageNumSize(User user); } //当 user 中的 pageNum!= null && pageSize!= null 时,会自动分页 List list = userMapper.selectByPageNumSize(user); //第六种,ISelect 接口方式 //jdk6,7用法,创建接口 Page page = PageHelper.startPage(1, 10).doSelectPage(new ISelect() { @Override public void doSelect() { userMapper.selectGroupBy(); } }); //jdk8 lambda用法 Page page = PageHelper.startPage(1, 10).doSelectPage(()-> userMapper.selectGroupBy()); //也可以直接返回PageInfo,注意doSelectPageInfo方法和doSelectPage pageInfo = PageHelper.startPage(1, 10).doSelectPageInfo(new ISelect() { @Override public void doSelect() { userMapper.selectGroupBy(); } }); //对应的lambda用法 pageInfo = PageHelper.startPage(1, 10).doSelectPageInfo(() -> userMapper.selectGroupBy()); //count查询,返回一个查询语句的count数 long total = PageHelper.count(new ISelect() { @Override public void doSelect() { userMapper.selectLike(user); } }); //lambda total=PageHelper.count(()->userMapper.selectLike(user)); ``` 下面对最常用的方式进行详细介绍 #### 1). RowBounds方式的调用 ```java List list=sqlSession.selectList("x.y.selectIf",null,new RowBounds(1,10)); ``` 使用这种调用方式时,你可以使用RowBounds参数进行分页,这种方式侵入性最小,我们可以看到,通过RowBounds方式调用只是使用了这个参数,并没有增加其他任何内容。 分页插件检测到使用了RowBounds参数时,就会对该查询进行物理分页。 关于这种方式的调用,有两个特殊的参数是针对 `RowBounds` 的,你可以参看上面的 **场景一** 和 **场景二** 注:不只有命名空间方式可以用RowBounds,使用接口的时候也可以增加RowBounds参数,例如: ```java //这种情况下也会进行物理分页查询 List selectAll(RowBounds rowBounds); ``` **注意:** 由于默认情况下的 `RowBounds` 无法获取查询总数,分页插件提供了一个继承自 `RowBounds` 的 `PageRowBounds`,这个对象中增加了 `total` 属性,执行分页查询后,可以从该属性得到查询总数。 #### 2). `PageHelper.startPage` 静态方法调用 除了 `PageHelper.startPage` 方法外,还提供了类似用法的 `PageHelper.offsetPage` 方法。 在你需要进行分页的 MyBatis 查询方法前调用 `PageHelper.startPage` 静态方法即可,紧跟在这个方法后的第一个**MyBatis 查询方法**会被进行分页。 ##### 例一: ```java //获取第1页,10条内容,默认查询总数count PageHelper.startPage(1, 10); //紧跟着的第一个select方法会被分页 List list = userMapper.selectIf(1); assertEquals(2, list.get(0).getId()); assertEquals(10, list.size()); //分页时,实际返回的结果list类型是Page,如果想取出分页信息,需要强制转换为Page assertEquals(182, ((Page) list).getTotal()); ``` ##### 例二: ```java //request: url?pageNum=1&pageSize=10 //支持 ServletRequest,Map,POJO 对象,需要配合 params 参数 PageHelper.startPage(request); //紧跟着的第一个select方法会被分页 List list = userMapper.selectIf(1); //后面的不会被分页,除非再次调用PageHelper.startPage List list2 = userMapper.selectIf(null); //list1 assertEquals(2, list.get(0).getId()); assertEquals(10, list.size()); //分页时,实际返回的结果list类型是Page,如果想取出分页信息,需要强制转换为Page, //或者使用PageInfo类(下面的例子有介绍) assertEquals(182, ((Page) list).getTotal()); //list2 assertEquals(1, list2.get(0).getId()); assertEquals(182, list2.size()); ``` ##### 例三,使用`PageInfo`的用法: ```java //获取第1页,10条内容,默认查询总数count PageHelper.startPage(1, 10); List list = userMapper.selectAll(); //用PageInfo对结果进行包装 PageInfo page = new PageInfo(list); //测试PageInfo全部属性 //PageInfo包含了非常全面的分页属性 assertEquals(1, page.getPageNum()); assertEquals(10, page.getPageSize()); assertEquals(1, page.getStartRow()); assertEquals(10, page.getEndRow()); assertEquals(183, page.getTotal()); assertEquals(19, page.getPages()); assertEquals(1, page.getFirstPage()); assertEquals(8, page.getLastPage()); assertEquals(true, page.isFirstPage()); assertEquals(false, page.isLastPage()); assertEquals(false, page.isHasPreviousPage()); assertEquals(true, page.isHasNextPage()); ``` #### 3). 使用参数方式 想要使用参数方式,需要配置 `supportMethodsArguments` 参数为 `true`,同时要配置 `params` 参数。 例如下面的配置: ```xml ``` 在 MyBatis 方法中: ```java List selectByPageNumSize( @Param("user") User user, @Param("pageNumKey") int pageNum, @Param("pageSizeKey") int pageSize); ``` 当调用这个方法时,由于同时发现了 `pageNumKey` 和 `pageSizeKey` 参数,这个方法就会被分页。params 提供的几个参数都可以这样使用。 除了上面这种方式外,如果 User 对象中包含这两个参数值,也可以有下面的方法: ```java List selectByPageNumSize(User user); ``` 当从 User 中同时发现了 `pageNumKey` 和 `pageSizeKey` 参数,这个方法就会被分页。 注意:`pageNum` 和 `pageSize` 两个属性同时存在才会触发分页操作,在这个前提下,其他的分页参数才会生效。 #### 3). `PageHelper` 安全调用 ##### 1. 使用 `RowBounds` 和 `PageRowBounds` 参数方式是极其安全的 ##### 2. 使用参数方式是极其安全的 ##### 3. 使用 ISelect 接口调用是极其安全的 ISelect 接口方式除了可以保证安全外,还特别实现了将查询转换为单纯的 count 查询方式,这个方法可以将任意的查询方法,变成一个 `select count(*)` 的查询方法。 ##### 4. 什么时候会导致不安全的分页? `PageHelper` 方法使用了静态的 `ThreadLocal` 参数,分页参数和线程是绑定的。 只要你可以保证在 `PageHelper` 方法调用后紧跟 MyBatis 查询方法,这就是安全的。因为 `PageHelper` 在 `finally` 代码段中自动清除了 `ThreadLocal` 存储的对象。 如果代码在进入 `Executor` 前发生异常,就会导致线程不可用,这属于人为的 Bug(例如接口方法和 XML 中的不匹配,导致找不到 `MappedStatement` 时), 这种情况由于线程不可用,也不会导致 `ThreadLocal` 参数被错误的使用。 但是如果你写出下面这样的代码,就是不安全的用法: ```java PageHelper.startPage(1, 10); List list; if(param1 != null){ list = userMapper.selectIf(param1); } else { list = new ArrayList(); } ``` 这种情况下由于 param1 存在 null 的情况,就会导致 PageHelper 生产了一个分页参数,但是没有被消费,这个参数就会一直保留在这个线程上。当这个线程再次被使用时,就可能导致不该分页的方法去消费这个分页参数,这就产生了莫名其妙的分页。 上面这个代码,应该写成下面这个样子: ```java List list; if(param1 != null){ PageHelper.startPage(1, 10); list = userMapper.selectIf(param1); } else { list = new ArrayList(); } ``` 这种写法就能保证安全。 如果你对此不放心,你可以手动清理 `ThreadLocal` 存储的分页参数,可以像下面这样使用: ```java List list; if(param1 != null){ PageHelper.startPage(1, 10); try{ list = userMapper.selectAll(); } finally { PageHelper.clearPage(); } } else { list = new ArrayList(); } ``` 这么写很不好看,而且没有必要。 ### 4. MyBatis 和 Spring 集成示例 如果和Spring集成不熟悉,可以参考下面两个 只有基础的配置信息,没有任何现成的功能,作为新手入门搭建框架的基础 - [集成 Spring 3.x](https://github.com/abel533/Mybatis-Spring/tree/spring3.x) - [集成 Spring 4.x](https://github.com/abel533/Mybatis-Spring) 这两个集成框架集成了 PageHelper 和 [通用 Mapper](https://github.com/abel533/Mapper)。 ### 5. Spring Boot 集成示例 - [pagehelper-spring-boot-samples](https://github.com/pagehelper/pagehelper-spring-boot/tree/master/pagehelper-spring-boot-samples) - https://github.com/abel533/MyBatis-Spring-Boot ================================================ FILE: wikis/zh/Important.md ================================================ ## 重要提示 ### `PageHelper.startPage`方法重要提示 只有紧跟在`PageHelper.startPage`方法后的第一个Mybatis的查询(Select)方法会被分页。 ### 请不要配置多个分页插件 请不要在系统中配置多个分页插件(使用Spring时,`mybatis-config.xml`和`Spring`配置方式,请选择其中一种,不要同时配置多个分页插件)! ### 分页插件不支持带有`for update`语句的分页 对于带有`for update`的sql,会抛出运行时异常,对于这样的sql建议手动分页,毕竟这样的sql需要重视。 ### 分页插件不支持嵌套结果映射 由于嵌套结果方式会导致结果集被折叠,因此分页查询的结果在折叠后总数会减少,所以无法保证分页结果数量正确。 ================================================ FILE: wikis/zh/Interceptor.md ================================================ ## Executor 拦截器高级教程 - QueryInterceptor 规范 这篇文档涉及下面几个方面 1. Executor query 方法介绍 2. 拦截器配置和调用顺序 3. 拦截 query 方法的技巧 4. 拦截 query 方法的规范 5. 如何配置不同的 Executor 插件 ### 1. Executor query 方法介绍 在 MyBatis 的拦截器的文档部分,我们知道 Executor 中的 query 方法可以被拦截,如果你真正写过这个方法的拦截器, 你可能会知道在 Executor 中的 query 方法有两个: ```java List query( MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, CacheKey cacheKey, BoundSql boundSql) throws SQLException; List query( MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler) throws SQLException; ``` 这两个方法的区别是第一个方法多两个参数 CacheKey 和 BoundSql,在多数情况下,我们用拦截器的目的就是针对 SQL 做处理,如果能够拦截第一个方法,可以直接得到 BoundSql 对象,就会很容易的得到执行的 SQL,也可以对 SQL 做处理。 虽然想的很好,但是 MyBatis 提供的 Exctutor 实现中,参数多的这个 query 方法都是被少的这个 query 方法在内部进行调用的。 在 `CachingExecutor` 中: ```java public List query( MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler) throws SQLException { BoundSql boundSql = ms.getBoundSql(parameterObject); CacheKey key = createCacheKey(ms, parameterObject, rowBounds, boundSql); return query(ms, parameterObject, rowBounds, resultHandler, key, boundSql); } ``` 在 `BaseExecutor` 中: ```java public List query( MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler) throws SQLException { BoundSql boundSql = ms.getBoundSql(parameter); CacheKey key = createCacheKey(ms, parameter, rowBounds, boundSql); return query(ms, parameter, rowBounds, resultHandler, key, boundSql); } ``` 上面这两个方法一样。由于第一个 query 方法在这里是内部调用,并且我们所有的拦截器都是层层代理的 `CachingExecutor` 或基于 `BaseExecutor` 的实现类,所以我们能拦截的就是参数少的这个方法。 分页插件开始从 Executor 拦截开始就一直是拦截的参数少的这个方法。但是从 5.0 版本开始,query 的这两个方法都可以被拦截了。在讲这个**原理**之前,我们先了解一下拦截器的执行顺序。 ### 2. 拦截器配置和调用顺序 拦截器的调用顺序分为两大种,第一种是拦截的不同对象,例如拦截 Executor 和 拦截 StatementHandler 就属于不同的拦截对象, 这两类的拦截器在整体执行的逻辑上是不同的,在 Executor 中的 query 方法执行过程中,会调用下面的代码: ```java public List doQuery( MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) throws SQLException { Statement stmt = null; try { Configuration configuration = ms.getConfiguration(); StatementHandler handler = configuration.newStatementHandler(wrapper, ms, parameter, rowBounds, resultHandler, boundSql); stmt = prepareStatement(handler, ms.getStatementLog()); return handler.query(stmt, resultHandler); } finally { closeStatement(stmt); } } ``` 在这段代码中,才会轮到 StatementHandler 去执行,StatementHandler 属于 Executor 执行过程中的一个子过程。 所以这两种不同类别的插件在配置时,一定是先执行 Executor 的拦截器,然后才会轮到 StatementHandler。所以这种情况下配置拦截器的顺序就不重要了,在 MyBatis 逻辑上就已经控制了先后顺序。 第二种拦截器的顺序就是指拦截同一种对象的同一个方法,例如都拦截 Executor 的 query 方法,这时你配置拦截器的顺序就会对这里有影响了。假设有如下几个拦截器,都是拦截的 Executor 的 query 方法。 ``` ``` 在`org.apache.ibatis.session.Configuration` 中有如下方法: ```java public void addInterceptor(Interceptor interceptor) { interceptorChain.addInterceptor(interceptor); } ``` MyBatis 会按照拦截器配置的顺序依次添加到 interceptorChain 中,其内部就是 `List interceptors`。再看 `Configuration` 中创建 Executor 的代码: ```java public Executor newExecutor(Transaction transaction, ExecutorType executorType) { executorType = executorType == null ? defaultExecutorType : executorType; executorType = executorType == null ? ExecutorType.SIMPLE : executorType; Executor executor; if (ExecutorType.BATCH == executorType) { executor = new BatchExecutor(this, transaction); } else if (ExecutorType.REUSE == executorType) { executor = new ReuseExecutor(this, transaction); } else { executor = new SimpleExecutor(this, transaction); } if (cacheEnabled) { executor = new CachingExecutor(executor); } executor = (Executor) interceptorChain.pluginAll(executor); return executor; } ``` 在调用 interceptorChain.pluginAll 之前,executor 就是前一节中的 `CachingExecutor` 或基于 `BaseExecutor` 的实现类。 然后看 interceptorChain.pluginAll 方法: ```java public Object pluginAll(Object target) { for (Interceptor interceptor : interceptors) { target = interceptor.plugin(target); } return target; } ``` 前面我们配置拦截器的顺序是1,2,3。在这里也会按照 1,2,3 的顺序被层层代理,代理后的结构如下: ```json Interceptor3:{ Interceptor2: { Interceptor1: { target: Executor } } } ``` 从这个结构应该就很容易能看出来,将来执行的时候肯定是按照 3>2>1>Executor>1>2>3 的顺序去执行的。 可能有些人不知道为什么3>2>1>Executor之后会有1>2>3,这是因为使用代理时,调用完代理方法后,还能继续进行其他处理。处理结束后,将代理方法的返回值继续往外返回即可。例如: ``` Interceptor3 前置处理 Object result = Interceptor2..query(4个参数方法); Interceptor3 后续处理 return result; ``` 对于 Interceptor2.query 方法也是相同的逻辑: ``` Interceptor2 前置处理 Object result = Interceptor1..query(4个参数方法); Interceptor2 后续处理 return result; ``` 同理 Interceptor1.query : ``` Interceptor1 前置处理 Object result = executor.query(4个参数方法); Interceptor1 后续处理 return result; ``` 叠加到一起后,如下: ``` Interceptor3 前置处理 Interceptor2 前置处理 Interceptor1 前置处理 Object result = executor.query(4个参数方法); Interceptor1 后续处理 Interceptor2 后续处理 Interceptor3 后续处理 return result; ``` 所以这个顺序就是 3>2>1>Executor>1>2>3。 在你弄清楚这个逻辑后,再继续往下看,因为后面的技巧会颠覆这个逻辑,所以才会有后面的规范以及如何配置不同的插件。 ### 3. 拦截 query 方法的技巧 上一节的内容中,对拦截器的用法是最常见的一种用法,所以才会出现这种都能理解的执行顺序。但是分页插件 5.0 不是这样,这个插件颠覆了这种顺序,这种颠覆其实也很普通,这也是本节要说的技巧。 在我写作 MyBatis 技术书籍的过程中(还没写完,已经因为分页插件占用了几周的写作时间),我就在考虑为什么不能拦截第一个 query(6个参数的)方法, 如果能拦截这个方法,就可以直接拿到 BoundSql,然后处理 SQL 就很容易实现其他的操作。 在第 1 节介绍为什么第一个 query 方法不能被拦截时,是因为下面这段代码: ```java public List query( MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler) throws SQLException { BoundSql boundSql = ms.getBoundSql(parameter); CacheKey key = createCacheKey(ms, parameter, rowBounds, boundSql); return query(ms, parameter, rowBounds, resultHandler, key, boundSql); } ``` 既然 `CachingExecutor` 或基于 `BaseExecutor` 的实现类只是这么简单的调用两个方法得到了 BoundSql 和 Cachekey,我们为什么不直接替代他们呢? 所以我们可以有类似下面的拦截器用法: ```java @Intercepts(@Signature(type = Executor.class, method = "query", args = {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class})) public class QueryInterceptor implements Interceptor { @Override public Object intercept(Invocation invocation) throws Throwable { Object[] args = invocation.getArgs(); MappedStatement ms = (MappedStatement) args[0]; Object parameterObject = args[1]; RowBounds rowBounds = (RowBounds) args[2]; ResultHandler resultHandler = (ResultHandler) args[3]; Executor executor = (Executor) invocation.getTarget(); BoundSql boundSql = ms.getBoundSql(parameterObject); //可以对参数做各种处理 CacheKey cacheKey = executor.createCacheKey(ms, parameterObject, rowBounds, boundSql); return executor.query(ms, parameterObject, rowBounds, resultHandler, cacheKey, boundSql); } @Override public Object plugin(Object target) { return Plugin.wrap(target, this); } @Override public void setProperties(Properties properties) { } } ``` 这个拦截器直接替代了原有 Executor 的部分逻辑,直接去调用了 6 个参数的方法,因而导致 4 个参数的后续方法被跳过了。但是由于这里的 executor 是代理对象 所以 6 个参数的 query 方法可以被代理了,这就扰乱了上一节中的执行顺序。 在上一节拦截器的例子中,做简单修改,将 ExecutorQueryInterceptor2 换成上面的 QueryInterceptor,配置如下: ``` ``` 代理后的结构如下: ```json Interceptor3:{ QueryInterceptor: { Interceptor1: { target: Executor } } } ``` 这时,调用顺序就变了,Interceptor3 执行顺序如下: ``` Interceptor3 前置处理 Object result = QueryInterceptor.query(4个参数方法); Interceptor3 后续处理 return result; ``` QueryInterceptor.query 执行逻辑如下: ``` Interceptor2 前置处理 Object result = executor.query(6个参数方法); Interceptor2 后续处理 return result; ``` 在 QueryInterceptor 中,没有继续执行 4个参数方法,而是执行了 6 个参数方法。 但是 Interceptor1 拦截的 4 个参数的方法,所以 Interceptor1 就被跳过去了,整体的执行逻辑就变成下面这样了: ``` Interceptor3 前置处理 Interceptor2 前置处理 Object result = executor.query(6个参数方法); Interceptor2 后续处理 Interceptor3 后续处理 return result; ``` 如果 Interceptor1 拦截的是 6 个参数的方法,因为 QueryInterceptor 获取的是 Interceptor1 代理的 executor 对象,那么 Interceptor1 就会被 QueryInterceptor 继续执行下去。 分页插件就是类似 QueryInterceptor 的执行逻辑,所以当你使用 5.0 版本之后的插件时,如果你还需要配置其他 Executor 的 query 插件,你就会遇到一些问题(可以解决,继续往下看)。 如果你是自己开发的插件,那么你按照下一节的规范去开发也不会遇到问题。如果你使用的其他人提供的插件,按照第 5 节的配置顺序也能解决问题。 ### 4. 拦截 query 方法的规范 QueryInterceptor 的逻辑就是进去的是 4 个参数的方法,出去的是 6 个参数的方法。这种处理方法不仅仅不方便和一般的 Excutor 拦截器搭配使用, 当出现两个以上类似 QueryInterceptor 的插件时,由于接口变了,类似 QueryInterceptor 插件也无法连贯的执行下去。 因而有必要解决这个问题。解决的办法就是使用统一的规范。经过规范后 QueryInterceptor 如下: ```java @Intercepts( { @Signature(type = Executor.class, method = "query", args = {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class}), @Signature(type = Executor.class, method = "query", args = {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class, CacheKey.class, BoundSql.class}), } ) public class QueryInterceptor implements Interceptor { @Override public Object intercept(Invocation invocation) throws Throwable { Object[] args = invocation.getArgs(); MappedStatement ms = (MappedStatement) args[0]; Object parameter = args[1]; RowBounds rowBounds = (RowBounds) args[2]; ResultHandler resultHandler = (ResultHandler) args[3]; Executor executor = (Executor) invocation.getTarget(); CacheKey cacheKey; BoundSql boundSql; //由于逻辑关系,只会进入一次 if(args.length == 4){ //4 个参数时 boundSql = ms.getBoundSql(parameter); cacheKey = executor.createCacheKey(ms, parameter, rowBounds, boundSql); } else { //6 个参数时 cacheKey = (CacheKey) args[4]; boundSql = (BoundSql) args[5]; } //TODO 自己要进行的各种处理 //注:下面的方法可以根据自己的逻辑调用多次,在分页插件中,count 和 page 各调用了一次 return executor.query(ms, parameter, rowBounds, resultHandler, cacheKey, boundSql); } @Override public Object plugin(Object target) { return Plugin.wrap(target, this); } @Override public void setProperties(Properties properties) { } } ``` 注意两个变化,第一个就是拦截器签名同时拦截了 4 个 和 6 个参数的方法,这样不管那个插件在前在后都会被执行。 第二个变化就是这段代码: ```java CacheKey cacheKey; BoundSql boundSql; //由于逻辑关系,只会进入一次 if(args.length == 4){ //4 个参数时 boundSql = ms.getBoundSql(parameterObject); cacheKey = executor.createCacheKey(ms, parameterObject, rowBounds, boundSql); } else { //6 个参数时 cacheKey = (CacheKey) args[4]; boundSql = (BoundSql) args[5]; } ``` 如果这个插件配置的靠后,是通过 4 个参数方法进来的,我们就获取这两个对象。如果这个插件配置的靠前,已经被别的拦截器处理成 6 个参数的方法了, 那么我们直接从 args 中取出这两个参数直接使用即可。取出这两个参数就保证了当其他拦截器对这两个参数做过处理时,这两个参数在这里会继续生效。 假设有个排序插件和分页插件,排序插件将 BoundSql 修改为带排序的 SQL 后,SQL 会继续交给分页插件使用。分页插件的分页 SQL 执行时,会保留排序去执行, 这样的规范就保证了两个插件都能正常的执行下去。 所以如果大家想要使用这种方式去实现拦截器,建议大家遵守这个规范。 这个规范对于已经存在的插件来说就没法控制了,但是仍然可以通过配置顺序来解决。 ### 5. 如何配置不同的 Executor 插件 当引入类似 QueryInterceptor 插件时,由于扰乱了原有的插件执行方式,当配置 Executor 顺序不对时会导致插件无法生效。 第 4 节中的例子: ``` ``` 首先执行顺序为 3>Query>1>Executor,由于 Query 是 4 或 6 个参数进来,6 个参数出去。 所以在 Query 前面执行的拦截器必须是 4 个的(Query 规范拦截器先后都能执行,需要根据逻辑配置先后)参数的,在 Query 后面执行的拦截器必须是 6 个参数的。 这个顺序对应到配置顺序时,也就是 4 个参数的配置在 QueryInterceptor 拦截器的下面,6 个参数的配置在 QueryInterceptor 拦截器的上面。 按照这个顺序进行配置时,就能保证拦截器都执行。 如果你想获得如分页插件(QueryInterceptor 规范)执行的 SQL,你就得按照 QueryInterceptor 规范去实现,否则只能配置在分页插件的下面,也就只能获得分页处理前的 SQL。 ================================================ FILE: wikis/zh/Test.md ================================================ ## 项目测试 为了保证分页插件的稳定性,项目中包含大量的单元测试,并且可以针对支持的数据库进行测试。 ### 分页插件多数据库测试 为了更方便的测试不同的数据库,在`src/test/resources`目录下增加了不同数据库的mybatis配置文件,通过修改`test.properties`中的配置可以让测试使用不同的配置进行测试。 `test.properties`内容: ```properties #首先需要在本机配置对应的数据库 #想要测试那个数据库,这里就写那个数据库 #这个值和test/resources中的数据库对应的文件夹名字相同 #目前可选为: #hsqldb #mysql #mariadb - 注意测试中的端口是3309(因为默认和mysql是一样的) #oracle #postgresql #sqlserver #db2 #h2 #derby database = hsqldb ``` 各种数据库对应的sql文件都在对应的目录中。