This tutorial will show how how to integrate MyBatis with the Data Access Object pattern (DAO) and MySQL for use in Java Web Apps.
In case you're not familiar, MyBatis is the new version of the iBatis Data Mapper Java Framework, which allows you to use a relational database with object-oriented applications.
If you're not familiar with the DAO pattern or the benefits of using it read more about it hereGeneric implementation of the DAO pattern.
Full code of this mybatis dao example tutorial is available on github here.
Step 1 - Define the interface
Create an IParentDAO interface to define the main method calls for all objects. This interface can be used as the parent for various DAO implementations. Here are the default CRUD methods that all objects will have
get(id) getByName(name) getAll() create(obj) update(object) delete(id)
Create the IParentDAO.java class
Step 2 - Create the base class
Create the MyBatisDAO abstract base class. This will be the default MyBatis implementation of the DAO. You can of course write a different one for JDBC, Spring etc.Feel free to remove the logging code if you don't need it. I usedLogback for that.
Naming Convetions
You'll notice there are four prefix constants defined in the class above.
The reason for this is to keep consistency between the sql query ids you will define in the mybatis mapper.xml files (see Step 4) and the method names defined in the MyBatisDAO class we're implementing.
This won't work exactly like ActiveRecord or similar frameworks where there is a pluralization engine but it will still simplify things a lot.
For example, if you have an object called Status for which you will create a DAO, you will have to define the following mybatis querries
Java Method | MyBatis Query Id | Convention |
---|---|---|
dao.get(1) | <select id="getStatus" ... | getClassName |
dao.getAll() | <select id="getAllStatus" ... | getAllClassName |
dao.getByName(String name) | <select id="getStatusByName" ... | getClassNameByName |
dao.create(obj) | <insert id="createStatus" ... | createClassName |
dao.update(obj) | <update id="updateStatus" ... | updateClassName |
dao.delete(id) | <delete id="deleteStatus" ... | deleteClassName |
Don't worry, this will make a lot more sense once you get to Step 4
Step 3 - Write the actual DAO classes
Now you need to implement your concrete DAO classes.
Let's say you have a simple object called Status which maps to a simple table, and has 2 attributes, an ID and a NAME. Think of it as an object you could use to represent the status of a task.I chose this to illustrate a very basic example here
The table for this object would look like this
ID | NAME |
---|---|
1 | Done |
2 | In Progress |
3 | Not Started |
And the java class (or DTO object) would look like this (Status.java)
Writing the DAO class for the Status object now becomes trivial since you're inheriting all the default CRUD methods from MyBatisDAO.java defined above.
Here's how the StatusDAO.java should look:
You'll notice here that all you need to do is call the constructor from the parent MyBatisDAO.java class. Now all the default CRUD methods are available for the StatusDAO.java class.
You are free of course to add any additional methods as needed here that go beyond the CRUD methods that were defined. For example something like
getStatusForBlog(Integer blogId).
See the full code example.
Both the MyBatisDAO.java and IParentDAO.java classes are included.
Of course you will still have to define the MyBatis mapper SQL statements for the default CRUD methods defined in MyBatisDAO.java, as well as additional SQLs for other DAO methods you choose to implement. Which brings us to the next step ...
Step 4 - Defining the mybatis mapper
The last major step in the puzzle, is writing the actual SQL that will implement all the default CRUD methods and any other methods you've implemented for the Status object.
Your code may differ of course, but note the use of the naming conventions for naming the sql statements which I talked about earlier.
That is the key to this whole thing, and it will make your life a lot easier when writing other DAOs which extend the MyBatisDAO class.
Here is an example of how the mapper file for the StatusDAO object would look like.
StatusMapper.xml
Note here the use of the mapper namespace which is the same as referenced by the MyBatisDAO abstract class.
It's used for convenience in this case, and generally you should be able to use multiple mapper files with the same namespace as long as the you don't have multiple queries with the same id across several xml mapper files (which would be a bad idea anyway)
Errors
Just a side note on some errors you may encounter.
If you call one of the default CRUD methods but don't define the appropriate query in the mapper.xml file, you will get an error like this:
org.apache.ibatis.exceptions.PersistenceException: ### Error querying database. Cause: java.lang.IllegalArgumentException: Mapped Statements collection does not contain value for mappers.getAllFrog ### Cause: java.lang.IllegalArgumentException: Mapped Statements collection does not contain value for mappers.getAllFrog
Wrapping it up
By this point I hope you've managed to build yourself a small but working DAO implementation based on the MyBatisDAO abstract class.
You can download the full code example for more a better overview.
It also contains a jUnit example, the mybatis configuration file (mybatis.config.xml) as well as the simple DDL statments for setting up the MySQL table.
Note:If you need to use this from a Servlet or Spring controller, see my other blog post aboutdefining a servletcontextlistener