A minimal JDBC example of offset-based pagination for flat entity queries — no Spring Data, pure SQL, clean architecture.
- Offset-based pagination with
LIMIT / OFFSETandCOUNT(*) - Using
package-privateclasses as an encapsulation boundary inside the infrastructure layer - Separating persistence projections from application-level read models via
ViewMapper
- Java 25
- Spring Boot
- Spring JDBC (
JdbcClient) - H2 (in-memory database)
application/
OwnerReadRepository ← port (interface)
OwnerView ← read model
PageQuery ← pagination input
PageResult<T> ← pagination output
infrastructure/
JdbcOwnerReadRepository ← JDBC implementation
OwnerProjection ← internal, never leaks out
ViewMapper ← projection → view
// page 0, 2 items per page
repository.findAllFlat(new PageQuery(0, 2));
// page 1, 2 items per page
repository.findAllFlat(new PageQuery(1, 2));Output:
=== page - 0 ===
PageResult[content=[OwnerView[id=1, name=jack1], OwnerView[id=2, name=jack2]], page=0, size=2, total=10]
=== page - 1 ===
PageResult[content=[OwnerView[id=3, name=jack3], OwnerView[id=4, name=jack4]], page=1, size=2, total=10]
PageQuery and PageResult have zero framework dependencies — copy them into any Java project.
Integration tests in src/test/java cover pagination correctness, last page with remainder, and edge cases including pages beyond total.
- persistence-flat-pagination-sorting-jdbc — adds multi-field sorting with SQL injection protection
- persistence-graph-pagination-jdbc — same approach over a multi-level object graph
./mvnw spring-boot:run