MyBatis
SQL-first Java persistence framework — maps SQL queries to Java objects with full control over SQL. Unlike JPA/Hibernate which generate SQL, MyBatis uses developer-written SQL: define SQL in XML mapper files or @Select/@Insert annotations, MyBatis handles parameter binding and result set mapping. Used extensively in enterprise Java (especially in organizations with complex legacy SQL or DBAs who write optimized SQL). Popular in Asian tech companies and systems requiring precise SQL control (financial systems, complex reports). MyBatis-Spring integration for Spring Boot auto-configuration.
Score Breakdown
⚙ Agent Friendliness
🔒 Security
#{} parameter binding prevents SQL injection. ${} string substitution requires careful use. TLS via JDBC URL. Explicit SQL writing makes security review of queries straightforward. No hidden ORM-generated queries.
⚡ Reliability
Best When
You need full SQL control for complex queries (financial reports, analytics, legacy databases), work with DBAs who write SQL, or are migrating from raw JDBC with minimal ORM overhead.
Avoid When
You want auto-generated CRUD (use Spring Data JPA), are building a new greenfield app without complex SQL needs, or your team prefers ORM over SQL-first development.
Use Cases
- • Write optimized agent database queries with full SQL control — MyBatis lets agent data access code use exact SQL with EXPLAIN-optimized queries, not ORM-generated SQL
- • Map complex agent SQL result sets to Java objects — @Results annotations or XML resultMaps for multi-join queries that ORMs struggle with
- • Migrate legacy Java agent systems from raw JDBC to cleaner mapper pattern — MyBatis adds structured query organization without full ORM migration
- • Implement dynamic agent SQL queries using MyBatis's <if>, <foreach>, <choose> XML tags — build queries conditionally based on agent filter criteria without string concatenation
- • Use MyBatis Generator (MBG) to auto-generate mapper interfaces from database schema — reverse-engineer agent database tables into typed Java mappers
Not For
- • Teams wanting auto-generated CRUD — JPA/Hibernate's @Entity and Spring Data repositories auto-generate findAll/findById/save; MyBatis requires writing SQL for everything
- • Rapid prototyping where SQL precision doesn't matter — Spring Data JPA is faster for scaffolding agent CRUD APIs; MyBatis's SQL writing overhead isn't justified for simple queries
- • Non-Java JVM stacks — use SQLAlchemy (Python), ActiveRecord (Ruby), or GORM (Go) for SQL mapping in other ecosystems
Interface
Authentication
Database access library — no auth concepts. Database credentials via Spring Boot datasource configuration or MyBatis SqlSessionFactory config.
Pricing
MyBatis is Apache 2.0 licensed, maintained by the MyBatis team. Free for all use.
Agent Metadata
Known Gotchas
- ⚠ XML mapper namespace must match interface fully-qualified name — mapper XML namespace='com.example.AgentMapper' must exactly match interface package; mismatch causes 'Mapped Statements collection does not contain value' at startup
- ⚠ #{} vs ${} parameter binding — #{param} uses PreparedStatement placeholders (SQL injection safe); ${param} is direct string substitution (SQL injection risk); always use #{} for values; ${tableName} only for structural SQL parts like table/column names
- ⚠ N+1 query with association mapping — <association> and <collection> tags in resultMap trigger per-row subqueries by default; use JOIN queries in SQL and <resultMap> with nested result mapping; don't use lazy loading without understanding its query impact
- ⚠ Spring transaction management requires @Transactional — MyBatis operations within @Transactional use the same SqlSession for rollback; without @Transactional, each mapper method gets its own session and auto-commits; multi-step agent operations need explicit transactions
- ⚠ MyBatis Generator creates non-overridable files — MBG regenerates Mapper.xml and Mapper.java overwriting manual customizations; use MBG's plugin mechanism or keep custom mappers in separate files that extend generated ones
- ⚠ TypeHandler registration for custom types — Java enums, LocalDate, UUID require TypeHandler registration in MyBatis config; missing TypeHandler causes 'Error setting non null for parameter' or incorrect value mapping at runtime
Alternatives
Full Evaluation Report
Detailed scoring breakdown, competitive positioning, security analysis, and improvement recommendations for MyBatis.
Scores are editorial opinions as of 2026-03-06.