The usual problem
However, Mybatis is not an ORM. It does not know your objects. It just knows SQL queries. So when you select the same thing with two different queries, you will get two different instances. This makes handling complex object relationships very involved. Also, since Mybatis does not keep track of you objects, saving changes becomes an even greater challenge Things like cascading persist just don't exist. So if you were to load and persist complex object trees, you would need to implement a lot of ORM logic on top of Mybatis.
The conceptBut there is a middle ground. It is called Ebean. Ebean reads JPA annotations, but does not implement JPA itself. It has a much simpler model. Ebean has a persistence context that guarantees object identity within transactions. But it does not "automagically" synchronize changes between memory and the database. You need to explicitly call "save" to persist changes to an object. You could view this as objects always being "detached". This is not entirely true, because with Ebean your objects keep track of changes themselves, so they are somewhere between what JPA calls "Managed" and "Detached". This makes reasoning about a program a lot simpler.
FeaturesEbean comes with nice criteria queries that support automatic join fetching. So if you ask for all employees who work in the "IT" department, you can write something like "eq("department.name", "IT")" and Ebean will know that it has to join the employee table and the department table to find the correct answer. You can also specify fetch strategies on a per-query basis. So if you have two different use cases, one where you always need a certain association and one where you don't need it, you can write two different queries, resulting in optimized performance Lazy loading just works, as Ebean can keep connections open after a transaction has finished in order to lazily load more data.
Ebean also has nice support for raw SQL, similar to what Mybatis can do, just a little less flexible. You can write classes that represent the result of a SQL query (like some aggregation result) and tell Ebean how to map the result set to the bean's fields. Batch processing is also supported in two ways. RawSQL objects never get attached to the persistence context, so they don't eat up your memory. And if you want to batch process Entities, you can use a visitor-like query that executes a callback for every entity found, but does not put those entities into the persistence context.
The configuration of Ebean is very pluggable, so you can change datasources, transaction management, naming conventions and a lot more. The source code is also neatly structured. So if you find something lacking, it is pretty easy to find the correct place for you enhancement. I was able to add a naming convention for embeddable objects (so you don't need @AttributeOverride so often) in about 5 lines of code.