mrkeyoor.com_
Wed 02 Sept 07:08 UTC
Dataevaluationupdated 02 Sept 2026

mybatis-3 review

MyBatis is a Java data mapper that connects application objects to SQL statements or stored procedures written in XML or annotations. It removes much of JDBC's repetitive result handling while leaving the query and transaction choices visible to the developer.

Verdict

Our MyBatis checkout installed in 636 seconds, then both the build and test commands stopped because Maven 3.9.9 did not meet the 3.9.16 minimum. Use MyBatis when SQL ownership is a design requirement and your Java team will manage mapper and session discipline. Choose an ORM for model-driven persistence, or a thinner JDBC layer when result maps and dynamic XML would add more structure than the application needs.

We ran it

Lab card: what happened when we ran mybatis-3Screenshot of mybatis-3 (mybatis.github.io/mybatis-3)
Install✓ · 636s
Build✗ · 10s
Tests✗ · 9sran, no count parsed
Repo2073 files~116,941 lines of source · 6.6 MB · 7 CI workflows

Answers from our run

Does mybatis-3 build from source?

Dependencies installed in 636 seconds, and the build failed. We cloned commit 673798b into a clean Debian container with 3 CPUs and no project-specific setup.

Do mybatis-3's tests pass?

The test command failed in our container, and its output did not report a pass or fail count.

Who should not use mybatis-3?

Teams that want an ORM to derive most persistence behavior from an object model: the README presents MyBatis as a data mapper whose SQL stays in XML or annotations.

What are the alternatives to mybatis-3?

jOOQ, Hibernate ORM, Jdbi. Our MyBatis checkout installed in 636 seconds, then both the build and test commands stopped because Maven 3.

Setup2/5636-second install; Maven 3.9.16 gate blocked build and tests
Docs4/5Deep manuals cover mapping, sessions, caching, and dynamic SQL
Community5/520,441 stars with active August 2026 issue and pull request work
Maturity5/5Long-lived 3.x API with current maintenance and release history

Who it’s for

Java teams that want to write and review the SQL their applications execute.
Developers mapping legacy schemas, stored procedures, or queries that do not fit a generated object model.
Spring or Guice users willing to add the matching MyBatis integration for session and transaction handling.
Maintainers who value explicit result maps and database-specific SQL over automatic persistence behavior.

Who it’s NOT for

Teams that want an ORM to derive most persistence behavior from an object model: the README presents MyBatis as a data mapper whose SQL stays in XML or annotations.
Reactive database applications built around R2DBC: the documented API acquires JDBC Connection objects and scopes work through SqlSession.
Services that cannot enforce session cleanup: the Java API warns that an unclosed thread-local session can leak transaction state or connections across reused web-server threads.
Users of MyBatis 3.5.19 with high-concurrency dynamic SQL who cannot investigate dependency risk: open issue 3574 reports blocking in OGNL, and the proposed upgrade was still under review.

Setup reality

Our sandbox install succeeded in 636 seconds. The build failed after 10 seconds, and the test command failed after 9 seconds. Both stopped at the same Maven enforcer rule: installed Maven 3.9.9 was below the required 3.9.16 minimum.

Using the published library needs a JDBC driver, a data source, database connection details, transaction configuration, and mapper SQL. MyBatis itself does not require a hosted account or API credential; your database may require credentials.

The source targets Java 11, while our run used JDK 21. Session lifecycle is a runtime concern: unmanaged sessions need explicit close and commit behavior. The repository has 7 CI workflow files but no Dockerfile, so contributors must supply a matching Maven and JDK environment.

MyBatis keeps the SQL visible

MyBatis sits between raw JDBC and a full object-relational mapper. You define a mapper interface, attach SQL through XML or annotations, and receive Java objects instead of manually walking a ResultSet. A SqlSessionFactory owns configuration, while each SqlSession executes statements and manages transaction scope. The appeal is control: a database query remains recognizable to the engineer reviewing it.

That control comes with a sizeable codebase and an explicit mapping model. commit 673798b contained 2,073 files and about 116,941 lines of source in a 6.6 MB checkout. Result maps describe how columns populate constructors, properties, collections, and nested objects. Simple rows can map by convention, but a complex join still asks someone to understand aliases, identifiers, association rules, and the resulting object graph.

XML and annotations both leave query design with you

The README calls simplicity the advantage over object-relational mapping, which is accurate only if your team prefers SQL to hidden persistence behavior. Mapper annotations keep short statements next to Java methods. XML is better suited to reusable fragments and detailed result maps. Neither route designs the query, manages a schema migration, or decides how vendor differences should behave. Those choices stay in application code and review.

Dynamic SQL covers if, choose, trim, where, set, and foreach. It can prevent dangling AND clauses and trailing commas without string concatenation. The same mechanism uses OGNL expressions, and the 116,941-line source tree reflects how much machinery sits behind a compact mapper file. Teams should test every meaningful combination of optional filters because syntactically tidy XML can still produce a slow or logically wrong query.

What happened when we ran it

Our sandbox install succeeded in 636 seconds, but the build exited with code 1 after 10 seconds. The Maven enforcer reported one precise problem: Maven 3.9.9 did not satisfy the allowed range beginning at 3.9.16. The log reached that rule before compilation, so it does not show whether the Java source would have compiled after the toolchain requirement was met.

The test command reached the same enforcer rule and failed after 9 seconds. It did not produce a test summary, which means we cannot claim that any tests passed or failed. This was commit 673798b in an unprivileged container with 3 CPUs, 10 GB of RAM, and JDK 21. The useful result is a reproducible toolchain mismatch, not a judgment about test quality.

Our scan found 7 CI workflow files, no Dockerfile, and no separate tests directory. The README does explain that Maven test groups vary by JDK and operating system, with container-backed cases excluded by default. A contributor therefore needs to read the workflow and POM, install Maven 3.9.16 or newer, and decide whether the default exclusions match the change being checked.

A session leak can become a transaction leak

MyBatis makes session behavior explicit. Opening a default session starts a transaction, obtains a JDBC connection from the configured data source, and uses the driver's isolation default. The Java guide says every opened session must be closed. Its thread-local SqlSessionManager warning is sharper: failure to close in a pooled server can carry a SQL session into another request and cause unpredictable transactions or connection leaks.

Spring and Guice integrations can own that lifecycle, but they are separate integration layers. Without them, use a try-with-resources block and decide when to commit or roll back. The 636-second source install tells you nothing about this runtime discipline. Before adoption, test failed writes, request cancellation, nested service calls, batch execution, and connection-pool exhaustion against the same transaction setup used in production.

Nested selects and namespace caches need deliberate limits

The mapping guide plainly names the N+1 select problem. Loading a list and then issuing a nested select for every row can look elegant in a result map while multiplying database calls. MyBatis supports joined result maps and multiple result sets, so the fix is available, but the framework cannot choose it for you. Query logging and database-level inspection still belong in performance testing.

Caching carries similar conditions. Each session has a local cache, while the optional second-level cache is bound to a mapper namespace and updates at transaction completion. The measured checkout had 2,073 files, yet the risk can hide in one <cache/> line: another namespace touching the same tables may require a shared cache reference or an explicit invalidation choice. Start without second-level caching unless its ownership is clear.

The January 2025 release is followed by active 2026 work

GitHub showed 20,441 stars and 209 combined issues and pull requests when fetched. Release 3.5.19 was published on January 2, 2025, while the repository was pushed on August 29, 2026. The dates do not support an abandonment claim. They show a stable published line alongside continued work on the next source state.

Issue 3574 also shows why release age and development activity must be read together. A user reported OGNL lock contention with 3.5.19, and pull request 3763 proposed an OGNL upgrade on August 31, 2026. That report is workload-specific and does not prove every MyBatis service will block. High-concurrency users should reproduce it with their dynamic queries before choosing the current release.

Pick it for explicit SQL, not automatic persistence

MyBatis earns its place when engineers want SQL to be a maintained application asset. It handles parameter binding, mapper proxies, result construction, transaction hooks, and configurable caches while allowing stored procedures and vendor-specific branches. The documentation is detailed enough to expose footguns such as N+1 queries and unclosed sessions instead of pretending they disappear.

The failed 10-second build and 9-second test steps make the contributor path less forgiving than the brief README suggests. For application use, the stronger question is whether the team wants to own every query and its mapping for years. If yes, MyBatis is mature and direct. If no, Hibernate, jOOQ, or Jdbi each offers a different place to put that complexity.

Alternatives

ProjectWhat it isPick it when
jOOQA Java SQL DSL with schema-generated types and commercial editions for some databases.pick this instead when compile-time query construction and generated schema types matter more than XML mapping.
Hibernate ORMA full Java ORM with entity state tracking, associations, and object-oriented queries.pick this instead when the domain model should drive persistence and handwritten SQL is the exception.
JdbiA smaller JDBC convenience layer with fluent and declarative APIs.pick this instead when you want direct SQL with less mapper configuration and fewer framework concepts.

What people are saying

  1. [velocity-scout] mybatis/mybatis-3

Sources

  1. MyBatis 3 repository and README
  2. MyBatis 3 getting started guide
  3. MyBatis 3 Java API guide
  4. MyBatis 3 SQL map XML guide
  5. MyBatis 3.5.19 release
  6. MyBatis issue 3574 about OGNL lock contention

More data reviews

awesome-quant · sequelize · google-maps-scraper · turso · TrackersListCollection · dash · the whole board →