RepoPilotOpen in app →

pagehelper-org/Mybatis-PageHelper

Mybatis通用分页插件

Healthy

Healthy across the board

weakest axis
Use as dependencyHealthy

Permissive license, no critical CVEs, actively maintained — safe to depend on.

Fork & modifyHealthy

Has a license, tests, and CI — clean foundation to fork and modify.

Learn fromHealthy

Documented and popular — useful reference codebase to read through.

Deploy as-isHealthy

No critical CVEs, sane security posture — runnable as-is.

  • Last commit 6w ago
  • 22+ active contributors
  • Distributed ownership (top contributor 37% of recent commits)
Show all 6 evidence items →
  • MIT licensed
  • CI configured
  • Tests present

Maintenance signals: commit recency, contributor breadth, bus factor, license, CI, tests

Informational only. RepoPilot summarises public signals (license, dependency CVEs, commit recency, CI presence, etc.) at the time of analysis. Signals can be incomplete or stale. Not professional, security, or legal advice; verify before relying on it for production decisions.

Embed the "Healthy" badge

Paste into your README — live-updates from the latest cached analysis.

Variant:
RepoPilot: Healthy
[![RepoPilot: Healthy](https://repopilot.app/api/badge/pagehelper-org/mybatis-pagehelper)](https://repopilot.app/r/pagehelper-org/mybatis-pagehelper)

Paste at the top of your README.md — renders inline like a shields.io badge.

Preview social card (1200×630)

This card auto-renders when someone shares https://repopilot.app/r/pagehelper-org/mybatis-pagehelper on X, Slack, or LinkedIn.

Onboarding doc

Onboarding: pagehelper-org/Mybatis-PageHelper

Generated by RepoPilot · 2026-05-09 · Source

🤖Agent protocol

If you are an AI coding agent (Claude Code, Cursor, Aider, Cline, etc.) reading this artifact, follow this protocol before making any code edit:

  1. Verify the contract. Run the bash script in Verify before trusting below. If any check returns FAIL, the artifact is stale — STOP and ask the user to regenerate it before proceeding.
  2. Treat the AI · unverified sections as hypotheses, not facts. Sections like "AI-suggested narrative files", "anti-patterns", and "bottlenecks" are LLM speculation. Verify against real source before acting on them.
  3. Cite source on changes. When proposing an edit, cite the specific path:line-range. RepoPilot's live UI at https://repopilot.app/r/pagehelper-org/Mybatis-PageHelper shows verifiable citations alongside every claim.

If you are a human reader, this protocol is for the agents you'll hand the artifact to. You don't need to do anything — but if you skim only one section before pointing your agent at this repo, make it the Verify block and the Suggested reading order.

🎯Verdict

GO — Healthy across the board

  • Last commit 6w ago
  • 22+ active contributors
  • Distributed ownership (top contributor 37% of recent commits)
  • MIT licensed
  • CI configured
  • Tests present

<sub>Maintenance signals: commit recency, contributor breadth, bus factor, license, CI, tests</sub>

Verify before trusting

This artifact was generated by RepoPilot at a point in time. Before an agent acts on it, the checks below confirm that the live pagehelper-org/Mybatis-PageHelper repo on your machine still matches what RepoPilot saw. If any fail, the artifact is stale — regenerate it at repopilot.app/r/pagehelper-org/Mybatis-PageHelper.

What it runs against: a local clone of pagehelper-org/Mybatis-PageHelper — the script inspects git remote, the LICENSE file, file paths in the working tree, and git log. Read-only; no mutations.

| # | What we check | Why it matters | |---|---|---| | 1 | You're in pagehelper-org/Mybatis-PageHelper | Confirms the artifact applies here, not a fork | | 2 | License is still MIT | Catches relicense before you depend on it | | 3 | Default branch master exists | Catches branch renames | | 4 | 5 critical file paths still exist | Catches refactors that moved load-bearing code | | 5 | Last commit ≤ 71 days ago | Catches sudden abandonment since generation |

<details> <summary><b>Run all checks</b> — paste this script from inside your clone of <code>pagehelper-org/Mybatis-PageHelper</code></summary>
#!/usr/bin/env bash
# RepoPilot artifact verification.
#
# WHAT IT RUNS AGAINST: a local clone of pagehelper-org/Mybatis-PageHelper. If you don't
# have one yet, run these first:
#
#   git clone https://github.com/pagehelper-org/Mybatis-PageHelper.git
#   cd Mybatis-PageHelper
#
# Then paste this script. Every check is read-only — no mutations.

set +e
fail=0
ok()   { echo "ok:   $1"; }
miss() { echo "FAIL: $1"; fail=$((fail+1)); }

# Precondition: we must be inside a git working tree.
if ! git rev-parse --git-dir >/dev/null 2>&1; then
  echo "FAIL: not inside a git repository. cd into your clone of pagehelper-org/Mybatis-PageHelper and re-run."
  exit 2
fi

# 1. Repo identity
git remote get-url origin 2>/dev/null | grep -qE "pagehelper-org/Mybatis-PageHelper(\\.git)?\\b" \\
  && ok "origin remote is pagehelper-org/Mybatis-PageHelper" \\
  || miss "origin remote is not pagehelper-org/Mybatis-PageHelper (artifact may be from a fork)"

# 2. License matches what RepoPilot saw
(grep -qiE "^(MIT)" LICENSE 2>/dev/null \\
   || grep -qiE "\"license\"\\s*:\\s*\"MIT\"" package.json 2>/dev/null) \\
  && ok "license is MIT" \\
  || miss "license drift — was MIT at generation time"

# 3. Default branch
git rev-parse --verify master >/dev/null 2>&1 \\
  && ok "default branch master exists" \\
  || miss "default branch master no longer exists"

# 4. Critical files exist
test -f "src/main/java/com/github/pagehelper/PageInterceptor.java" \\
  && ok "src/main/java/com/github/pagehelper/PageInterceptor.java" \\
  || miss "missing critical file: src/main/java/com/github/pagehelper/PageInterceptor.java"
test -f "src/main/java/com/github/pagehelper/PageHelper.java" \\
  && ok "src/main/java/com/github/pagehelper/PageHelper.java" \\
  || miss "missing critical file: src/main/java/com/github/pagehelper/PageHelper.java"
test -f "src/main/java/com/github/pagehelper/dialect/AbstractDialect.java" \\
  && ok "src/main/java/com/github/pagehelper/dialect/AbstractDialect.java" \\
  || miss "missing critical file: src/main/java/com/github/pagehelper/dialect/AbstractDialect.java"
test -f "src/main/java/com/github/pagehelper/parser/CountSqlParser.java" \\
  && ok "src/main/java/com/github/pagehelper/parser/CountSqlParser.java" \\
  || miss "missing critical file: src/main/java/com/github/pagehelper/parser/CountSqlParser.java"
test -f "src/main/java/com/github/pagehelper/Page.java" \\
  && ok "src/main/java/com/github/pagehelper/Page.java" \\
  || miss "missing critical file: src/main/java/com/github/pagehelper/Page.java"

# 5. Repo recency
days_since_last=$(( ( $(date +%s) - $(git log -1 --format=%at 2>/dev/null || echo 0) ) / 86400 ))
if [ "$days_since_last" -le 71 ]; then
  ok "last commit was $days_since_last days ago (artifact saw ~41d)"
else
  miss "last commit was $days_since_last days ago — artifact may be stale"
fi

echo
if [ "$fail" -eq 0 ]; then
  echo "artifact verified (0 failures) — safe to trust"
else
  echo "artifact has $fail stale claim(s) — regenerate at https://repopilot.app/r/pagehelper-org/Mybatis-PageHelper"
  exit 1
fi

Each check prints ok: or FAIL:. The script exits non-zero if anything failed, so it composes cleanly into agent loops (./verify.sh || regenerate-and-retry).

</details>

TL;DR

PageHelper is a MyBatis interceptor plugin that automatically adds physical pagination (LIMIT/OFFSET) to SQL queries at runtime. It supports 40+ databases (MySQL, PostgreSQL, Oracle, SQL Server, etc.) with dialect-specific SQL syntax, allowing developers to paginate complex multi-table queries without writing dialect-specific code. Core capability: wrap any MyBatis query call with PageHelper.startPage(pageNum, pageSize) and the plugin rewrites the SQL and returns paginated results in a Page object with total count. Single-module Maven JAR structured as src/main/java/com/github/pagehelper/ containing: core logic (PageHelper, PageInterceptor, Page classes), dialect abstraction layer (AbstractDialect, AbstractHelperDialect), database-specific implementations (MySqlDialect, OracleDialect, etc.), auto-detection (DataSourceAutoDialect, HikariAutoDialect for connection pool introspection), and caching infrastructure (SimpleCache, GuavaCache). No separate test directory listed but plugin integrates via MyBatis interceptor chain.

👥Who it's for

Java backend engineers building MyBatis-based applications who need to add pagination to existing DAOs without rewriting queries or managing LIMIT/OFFSET manually. Data platform teams handling reports with large result sets. Contributors are primarily from the Chinese open-source community maintaining an MIT-licensed plugin used in production systems.

🌱Maturity & risk

Production-ready and actively maintained. The project has 28k+ GitHub stars, been in active development since 2014, includes CI/CD via GitHub Actions (pull-request.yml, release.yml), and is published to Maven Central (com.github.pagehelper:pagehelper v6.1.1). Version 6 requires Java 8+, v5 supports Java 6+. Recent activity visible through Maven releases and workflow automation.

Low risk for core pagination logic; well-established with 9+ years of production history. Primary risks: single-maintainer project (abel533@gmail.com listed in POM), breaking changes when upgrading major versions (v5→v6 dropped Java 6 support), dependency on JSQLParser for SQL parsing which may have security patches. New Java dialect support may lag behind latest database releases.

Active areas of work

v6.1.1 release is current version in pom.xml. GitHub workflows show automated PR validation and release pipelines. JSQLParser compatibility patch file (jsqlparser4_7兼容性改动.patch) indicates ongoing compatibility maintenance. No specific milestone data visible but typical activity includes dialect updates for new database versions and interceptor chain refinements.

🚀Get running

git clone https://github.com/pagehelper/Mybatis-PageHelper.git
cd Mybatis-PageHelper
mvn clean install
mvn test

Daily commands: This is a library JAR, not an executable app. Build with mvn clean package. Integration is via MyBatis XML config: <plugin interceptor="com.github.pagehelper.PageInterceptor"></plugin> or annotation-based Spring config. Run tests: mvn test.

🗺️Map of the codebase

  • src/main/java/com/github/pagehelper/PageInterceptor.java — Core MyBatis interceptor that hooks into query execution; all pagination logic flows through here as the entry point.
  • src/main/java/com/github/pagehelper/PageHelper.java — Primary public API for setting pagination parameters; developers use this to start pagination on any query.
  • src/main/java/com/github/pagehelper/dialect/AbstractDialect.java — Base class for all database-specific SQL dialects; defines the contract for pagination SQL generation across different databases.
  • src/main/java/com/github/pagehelper/parser/CountSqlParser.java — Transforms SELECT queries into COUNT queries for fetching total record count; critical for pagination metadata.
  • src/main/java/com/github/pagehelper/Page.java — Container class holding pagination state (pageNum, pageSize, total); passed through thread-local storage during query execution.
  • src/main/java/com/github/pagehelper/PageProperties.java — Configuration object for all PageHelper settings (dialect, reasonablePage, supportMethodsArguments, etc.); initialized from properties or annotations.
  • src/main/java/com/github/pagehelper/BoundSqlInterceptor.java — Interface for intercepting and modifying bound SQL before execution; allows custom SQL transformation pipeline.

🛠️How to make changes

Add Support for a New Database Dialect

  1. Create a new dialect class extending AbstractDialect or AbstractHelperDialect in src/main/java/com/github/pagehelper/dialect/helper/ (src/main/java/com/github/pagehelper/dialect/helper/NewDbDialect.java)
  2. Implement getPageSql() to generate pagination SQL using the new database's syntax (e.g., OFFSET/FETCH for new DB) (src/main/java/com/github/pagehelper/dialect/helper/NewDbDialect.java)
  3. Register the dialect name in the dialect auto-detection mapping within PageInterceptor or add manual configuration support in PageProperties (src/main/java/com/github/pagehelper/PageInterceptor.java)
  4. Optionally create a RowBoundsDialect variant in src/main/java/com/github/pagehelper/dialect/rowbounds/ if RowBounds pagination is needed (src/main/java/com/github/pagehelper/dialect/rowbounds/NewDbRowBoundsDialect.java)

Add a Custom SQL Transformation via BoundSqlInterceptor

  1. Create a class implementing BoundSqlInterceptor interface (src/main/java/com/github/pagehelper/BoundSqlInterceptor.java)
  2. Implement intercept() method to modify the BoundSql object before query execution (e.g., add hints, rewrite clauses) (src/custom/CustomBoundSqlInterceptor.java)
  3. Register the interceptor in PageProperties or PageBoundSqlInterceptors to add it to the chain (src/main/java/com/github/pagehelper/PageProperties.java)

Customize Count SQL Generation

  1. Create a class implementing CountSqlParser interface or extending DefaultCountSqlParser (src/main/java/com/github/pagehelper/parser/CountSqlParser.java)
  2. Override getCountSql() to generate custom COUNT SQL logic (e.g., apply custom aggregations or filtering) (src/custom/CustomCountSqlParser.java)
  3. Configure the custom parser in PageProperties under the countSql property or register via PageParserFactory if it exists (src/main/java/com/github/pagehelper/PageProperties.java)

Implement Auto Dialect Detection for a New Connection Pool

  1. Create a class extending DataSourceAutoDialect in src/main/java/com/github/pagehelper/dialect/auto/ (src/main/java/com/github/pagehelper/dialect/auto/NewPoolAutoDialect.java)

🪤Traps & gotchas

  1. Thread-local storage: PageHelper.startPage() uses ThreadLocal to hold pagination context — must be called in same thread as MyBatis query execution; async/CompletableFuture can lose context. 2) Dialect auto-detection requires datasource object accessible at runtime — fails silently if helperDialect property not set and datasource type not recognized. 3) Subqueries in WHERE clause may cause incorrect count queries if not wrapped in parentheses; see wikis/zh/Important.md. 4) rowBoundsWithFistPage=true changes RowBounds behavior (off by default) affecting legacy code. 5) JSQLParser version conflicts if your project pins a different version — watch dependency tree.

💡Concepts to learn

  • MyBatis Interceptor Chain — PageHelper implements MyBatis's plugin.Interceptor interface to hook into Executor.query() lifecycle; understanding interceptor ordering is critical when combining PageHelper with other plugins like caching or logging.
  • SQL Dialect Abstraction — Different databases have incompatible LIMIT/OFFSET syntaxes (MySQL: LIMIT 10,20; Oracle: ROWNUM; SQL Server: OFFSET 10 ROWS FETCH NEXT 20); PageHelper's dialect pattern encapsulates these differences, essential to understand for adding new database support.
  • ThreadLocal for Pagination Context — PageHelper uses ThreadLocal to store pageNum and pageSize between startPage() call and Executor.query() interception; critical gotcha for async/parallel execution and Spring transaction proxies.
  • Datasource Auto-Detection — PageHelper introspects connection pool type (HikariCP, Druid, C3P0, Tomcat) to infer database dialect without manual config; requires understanding JDBC metadata API and connection pool APIs.
  • Query Rewriting via BoundSQL — PageHelper intercepts MyBatis's BoundSQL (parsed SQL with placeholders replaced) to append LIMIT/OFFSET and generate count queries; understanding BoundSQL structure is key to implementing custom BoundSqlInterceptor chains.
  • Physical vs Logical Pagination — PageHelper performs physical pagination (database-level LIMIT/OFFSET) unlike RowBounds (app-level filtering); choosing between them affects performance on large datasets; understanding tradeoffs is essential for contributors.
  • Composite Interceptor Chains — BoundSqlInterceptorChain allows stacking multiple SQL transformers; contributors implementing caching, logging, or query optimization need to understand ordering and how PageHelper chains with other interceptors.
  • pagehelper/pagehelper-spring-boot-starter — Official Spring Boot starter that auto-configures PageHelper via PageProperties, eliminating manual MyBatis XML config
  • mybatis/mybatis-3 — Core MyBatis framework that PageHelper extends via Interceptor plugin API
  • baomidou/mybatis-plus — Alternative MyBatis enhancement library with built-in pagination, dynamic SQL, and code generation — direct competitor with integrated approach vs PageHelper's interceptor pattern
  • jsqlparser/JSqlParser — SQL parsing library that PageHelper uses to rewrite queries for pagination compatibility across dialects
  • alibaba/druid — Alibaba's connection pool with auto-dialect detection integration that PageHelper uses via DruidAutoDialect

🪄PR ideas

To work on one of these in Claude Code or Cursor, paste: Implement the "<title>" PR idea from CLAUDE.md, working through the checklist as the task list.

Add comprehensive unit tests for dialect auto-detection classes

The dialect/auto directory contains 8 AutoDialect implementations (C3P0AutoDialect, DruidAutoDialect, HikariAutoDialect, etc.) but there are no visible test files in the structure. These classes are critical for auto-detecting database types from connection pools. Adding unit tests would ensure each dialect correctly identifies its target database and prevent regressions when updating datasource library versions.

  • [ ] Create src/test/java/com/github/pagehelper/dialect/auto directory
  • [ ] Add unit tests for each AutoDialect class testing: correct pool type detection, fallback behavior, and edge cases
  • [ ] Test DataSourceAutoDialect and DataSourceNegotiationAutoDialect with mock DataSource objects
  • [ ] Verify DefaultAutoDialect fallback logic when unknown datasource types are encountered
  • [ ] Add integration tests that verify dialect selection in a multi-datasource environment

Add unit tests for BoundSqlInterceptor chain execution and BoundSqlInterceptorChain

The BoundSqlInterceptor.java and BoundSqlInterceptorChain.java files suggest a chain-of-responsibility pattern for intercepting bound SQL, but there's no visible test coverage. This is a core component that affects SQL modification behavior. Tests should verify chain ordering, exception handling, and interceptor interactions.

  • [ ] Create src/test/java/com/github/pagehelper/BoundSqlInterceptorChainTest.java
  • [ ] Test BoundSqlInterceptorChain.addInterceptor() and execution order
  • [ ] Add tests for multiple interceptors in sequence and verify each receives correct BoundSql state
  • [ ] Test exception handling when an interceptor in the chain throws an exception
  • [ ] Add tests for edge cases: empty chain, null interceptors, and concurrent chain execution

Add integration tests for PageProperties configuration and PageParam binding

PageProperties.java handles configuration binding and PageParam.java represents pagination parameters, but there's no visible test coverage for property binding from configuration files or parameter resolution. This is critical for ensuring users can configure PageHelper via application.properties/yml and use PageParam in method signatures correctly.

  • [ ] Create src/test/java/com/github/pagehelper/PagePropertiesTest.java
  • [ ] Test loading PageProperties from Spring Boot application.properties and application.yml configurations
  • [ ] Verify all configurable properties (reasonable, pageSizeZero, offsetAsPageNum, etc.) are correctly bound
  • [ ] Create src/test/java/com/github/pagehelper/PageParamTest.java for PageParam binding
  • [ ] Test PageParam used as method parameter with PageHelper.startPage() and in lambda expressions
  • [ ] Add tests for invalid configurations and verify proper error messages

🌿Good first issues

  • Add unit test coverage for AbstractRowBoundsDialect.java — currently no test file visible in the structure; implement tests for rowbounds-to-limit translation for MySQL, PostgreSQL, and Oracle dialects.
  • Document the BoundSqlInterceptor extension pattern with a working example in wikis/ — add code sample showing how to create a custom interceptor that logs slow queries before pagination applies.
  • Implement dialect support for newer databases listed in README but missing from dialect/helper/ (e.g., TiDB, CockroachDB, Vitess) by extending AbstractHelperDialect with their LIMIT syntax and registering in AutoDialect.registerDialectAlias().

Top contributors

Click to expand

📝Recent commits

Click to expand
  • 1399246 — docs: 补充 HowToUse 参数文档,新增 5 个缺失参数 (abel533)
  • 0a66c6a — docs: update wiki documentation for 6.1.1 release (abel533)
  • 5366677 — chore: migrate from OSSRH to Maven Central Portal (abel533)
  • b4212c4 — Set Liberapay username in FUNDING.yml (pagehelper)
  • 7d0422f — feat: 添加华为云 GaussDB 数据库分页支持 (abel533)
  • 8eca2e2 — fix: Correct ORDER BY parameter handling in count queries (issue 868) (abel533)
  • b92eaab — fix:质量检测修改 (彭卫东)
  • 9b91c3b — fix:质量检测修改 (彭卫东)
  • 70520cc — fix:Fix: 修复含特殊 ORDER BY 的查询生成总数 SQL 时的语法错误 (彭卫东)
  • 4db191c — 发布 6.1.1 (liuzenghui)

🔒Security observations

The Mybatis-PageHelper codebase presents moderate security concerns primarily around SQL injection risks due to dynamic SQL parsing and manipulation. While the project uses established libraries like JSQLParser, there are insufficient input validation mechanisms visible in the provided code structure. The auto-dialect detection and dynamic SQL building features without explicit security controls represent the highest risk areas. The project lacks explicit security documentation and guidelines for secure usage. Dependency management should be verified to ensure no known vulnerabilities exist in underlying libraries. Overall security posture requires improvements in input validation,

  • High · SQL Injection Risk in Query Parsing — src/main/java/com/github/pagehelper/parser/CountSqlParser.java, src/main/java/com/github/pagehelper/parser/OrderBySqlParser.java. The codebase contains SQL parsing and manipulation logic (CountSqlParser, OrderBySqlParser) that processes user-supplied SQL queries. Without proper input validation and parameterization, there is a risk of SQL injection attacks if user input is not properly sanitized before being passed to these parsers. Fix: Ensure all user-supplied input is properly validated and parameterized. Use prepared statements and avoid string concatenation for SQL building. Implement input validation to reject malicious SQL patterns.
  • High · Dynamic SQL Construction Without Validation — src/main/java/com/github/pagehelper/dialect/replace/, src/main/java/com/github/pagehelper/dialect/helper/. The dialect replacement classes (RegexWithNolockReplaceSql, SimpleWithNolockReplaceSql) and various dialect helper classes perform dynamic SQL string manipulation and regex-based replacements. These operations could be vulnerable to injection if the source SQL is not properly validated. Fix: Implement comprehensive input validation for all SQL modifications. Use parameterized approaches instead of string manipulation. Consider using JSQLParser library more defensively with validation.
  • Medium · Potential Dependency Vulnerability - JSQLParser — pom.xml. The codebase relies on JSQLParser library (indicated by the patch file 'jsqlparser4_7兼容性改动.patch'). The specific version is not clearly visible in the provided POM excerpt, which could mean outdated or vulnerable versions are being used. Fix: Explicitly specify JSQLParser version in POM and ensure it's updated to the latest stable version. Run regular dependency vulnerability scans using OWASP Dependency-Check or Snyk.
  • Medium · Missing Security Headers and Configuration Validation — src/main/java/com/github/pagehelper/PageProperties.java, src/main/java/com/github/pagehelper/PageInterceptor.java. The PageProperties and PageInterceptor classes handle configuration but there's no visible validation of sensitive parameters. No indication of security validation for dialect selection or interceptor configuration. Fix: Implement strict validation of all configuration parameters. Whitelist allowed dialects and properties. Log security-relevant configuration changes.
  • Medium · Insufficient Input Validation in Auto-Dialect Detection — src/main/java/com/github/pagehelper/dialect/auto/. The AutoDialect and various Auto*Dialect classes automatically detect database dialects. Improper validation could allow an attacker to influence dialect selection, potentially leading to SQL injection through dialect-specific vulnerabilities. Fix: Implement strict validation of datasource metadata. Use explicit dialect configuration rather than auto-detection when possible. Log dialect selection for audit trails.
  • Low · Missing Security Documentation — README.md, README_en.md. While the README and documentation are present, there is no explicit security guidelines or best practices documentation for users regarding secure usage of the pagination plugin. Fix: Add a SECURITY.md file documenting security best practices, known limitations, and secure configuration guidelines. Include input validation recommendations for users.
  • Low · Cache Implementation Security — src/main/java/com/github/pagehelper/cache/SimpleCache.java, src/main/java/com/github/pagehelper/cache/GuavaCache.java. The SimpleCache and GuavaCache implementations cache SQL and pagination data. If sensitive data is cached without proper access controls, it could be exposed. Fix: Ensure cached data doesn't include sensitive information. Implement cache expiration policies. Consider encrypting cached data at rest if sensitive information is cached.

LLM-derived; treat as a starting point, not a security audit.


Generated by RepoPilot. Verdict based on maintenance signals — see the live page for receipts. Re-run on a new commit to refresh.

Healthy signals · pagehelper-org/Mybatis-PageHelper — RepoPilot