MyBatis vs. Other ORMs



Naresh Bhatia

Naresh is a software architect in the Boston area. He started Archfirst after realizing that technologists spend too much time fighting technologies instead of solving real-world problems. Archfirst is a place where we can all learn best practices and techniques to make software development easier.


JoinJS – An Alternative to Complex ORMs 10th August, 2015

WordPress Domain Model 21st June, 2015

MyBatis vs. Other ORMs

Posted on .

Object-Relational Mapping (ORM) frameworks allow us to access relational databases from object-oriented languages. Over the years, I have used several ORMs – Hibernate/JPA for Java, Bookshelf.js and Sequelize for JavaScript, just to name a few. I was never completely satisfied with these solutions because in one way or another, they did not match my way of thinking. Recently, I tried MyBatis and it was a breath of fresh air! Let me explain why.

Domain entities should be free of persistence concerns

If you follow Domain-Driven Design, you probably subscribe to the idea that domain entities should stand on their own. You should not have to drag along a persistence framework with them. Domain entities form the inner core of the Hexagonal Architecture, which focuses only on the business logic. You should be able to stand up this core any way you want – by constructing new objects or retrieving them from a database, the core itself should not care. Many ORMs pollute this core with persistence concerns, and I don’t like that. For example, Bookshelf forces you to define entities using Model objects, and Sequelize does the same using sequelize.define( ). This creates “hidden” properties and methods inside the entities that teach them to persist themselves. I would rather have pure Java/JavaScript objects that focus on business logic, and then teach the persistence framework to persist them.

Well, that’s exactly what MyBatis does. Entities are POJOs that know nothing about persistence (see here). Instead you teach MyBatis how to save and retrieve these entities using SQL statements and result maps (see here). For trivial objects, you don’t even have to define result maps, MyBatis figures them out automatically.

Give me control over SQL

For any serious project that uses a relational database, you can’t escape learning SQL. Most ORMs try to insulate you from SQL by providing higher level abstractions. However in exchange, they force you to learn a new API or an abstract query language. These APIs/query languages generate SQL anyway, so the only difference is that you don’t know what they are generating until you pop open the hood. In many cases, a query that I can write in a single statement, will be generated in two or more statements, reducing performance. Now I am suddenly going back to the ORM and tweaking it to produce a more efficient query. Sometimes the API is not rich enough to do everything I want, and I have to escape into SQL land anyway. Why bother with all this? If I have to know SQL anyway, why not just write it myself and optimize it directly? Teaching the framework to map the result into objects is much easier.

Guess what, that’s exactly what MyBatis does – see the result map here. It teaches MyBatis how to map a query result in to a Transaction object with references to an Account and a Category. I end up with much cleaner and understandable code.


I hope you can see why I like MyBatis. This will be my default ORM for Java going forward. However I have yet to see a comparable solution for JavaScript. If there was such a solution, would you switch to it? I would love to hear your thoughts.


Here are the two projects I used for comparing MyBatis to other ORMs:


Naresh Bhatia

Naresh is a software architect in the Boston area. He started Archfirst after realizing that technologists spend too much time fighting technologies instead of solving real-world problems. Archfirst is a place where we can all learn best practices and techniques to make software development easier.

  • user

    AUTHOR Antonino

    Posted on 10:17 pm March 10, 2016.

    Hi Naresh!

    Nice post! very simple and well explained! 🙂
    And I completely agree with you, MyBatis is the BEST option to solve the real problems with the SQL Databases.

    MyBatis abstracts correctly the complex concerns from DataBase to Java POJO models and viceversa.

    More control.
    Non intrusive.
    More maintainable.
    NO Lazy Loading exceptions!!

    JPA is the right choice for the persistence standard in Java but MyBatis is a heavyweight dude for the “tricky” real life.


  • user

    AUTHOR Damian

    Posted on 8:16 am May 13, 2016.

    Can you explain what this kind of mapping will return in as result in Java? Will it return as many transaction objects as SQL Query rows? SQL will duplicate transactions if for example there are more than one account or category associated with a transaction.

    SELECT AS id,
    t.txn_date AS txn_date,
    t.payee AS payee,
    t.memo AS memo,
    t.amount AS amount, AS account_id, AS account_name, AS category_id, AS category_name
    FROM transactions t
    LEFT OUTER JOIN accounts a
    ON t.account_id =
    LEFT OUTER JOIN categories c
    ON t.category_id =
    WHERE = #{id}

  • user

    AUTHOR Naresh Bhatia

    Posted on 7:53 pm May 30, 2016.

    Hi Damian,

    If there are more that one accounts or categories associated with one transaction, then yes, multiple rows will be returned for the transaction. However in my example, there is only one account and one category associated with each transaction. So only one row per transaction will be returned.

    Hope that helps.

  • user

    AUTHOR Ruby

    Posted on 11:44 am June 29, 2016.

    I have used MYBatis (Ibatis then) for more than 2 years and I totally prefer that over any other persistence framework. Especially when the DB design is not completely finalized , MYBatis made life real easy.

  • user

    AUTHOR Sandro Oliveira

    Posted on 11:42 am July 26, 2016.

    Hi Naresh,

    Nice post!

    I have been using MyBatis in a certain project in my company and I am enjoying it, however I am facing a issue:

    How can I create one query DB-Independent by using MyBatis?

    It seems that the API supports multi-db vendors DB, however, I have to deal with specific statments of each type of data base, for example: if I want to limit a query in Mysql I have to use LIMIT and if I want to run the same query against to an Oracle DB, I have to use ROWNUM <= X.

    Is it possible to create an only query which uses vendors drivers to translate it to native sql for each type of DB just like HQL in Hibernate?

  • Leave a Reply

    View Comments (5) ...