Using MyBatis 3 with Spring 3 Using Mapper XML Files
Recently I started to work on design an application as a part of a new project assigned to me at my work place. Since this is totally a new application to be developed from scratch, I got liberty/flexibility to choose the tools/frameworks which will form the foundation of the application. With lots of frameworks to choose from and many choices available for different tiers, I started evaluating each framework against the requirement of the application vs where it fits in which tier. When I came to data access tier (resource tier as some say), I realized that MyBatis (new name of iBatis after it moved to Google code from Apache) was best fit as ORM framework. I also decided to use Spring 3.x as DI framework and we all know how well MyBatis/iBatis and Spring (beans, data access, transaction etc) gel with each other. Using Spring's DI, declarative transaction management and MyBatis' query externalization, we as a developer can concentrate on implementing application/business logic and keep rest of the stuff like transaction management, JDBC resource management etc to be "headache" of container/frameworks.
So as I decided to go with MyBatis, I came to know that Spring 3.0 development finished first then MyBatis 3 and hence there is no official support in Spring 3.0 for MyBatis 3.0. Its expected to be there in Spring 3.1 release (Source: Spring-MyBatis integration RC2 reference doc). But thanks to MyBatis community, there is already a project for myabtis-spring integrations. At start I struggled a bit on how to wire Spring beans, dao with MyBatis mapper configuration files. As I was googling around, I stumbled upon a very good post by Giovanni Cuccu on this. It was very enlightening and provided me a good start. I created a maven/spring/mybatis project in my eclipse and started writing down some quick and crude code to test out. As soon as I tried to run my sample code I encountered...
java.lang.IllegalArgumentException: Property 'sqlSessionTemplate' is requiredAfter debugging the mybatis-spring integration source code, I found that since I was using Spring DAO using mybatis-spring integration, org.mybatis.spring.support.SqlSessionDaoSupport class' checkDaoConfig explicitly checks for thesqlSessionTemplate property to be defined. After trying for some time and to no success, I changed my DAO implementation to be a mapper interface using MapperFactoryBean. This eliminated of having a class implementing SqlSessionDaoSupport just to invoke Spring's SqlMapClientTemplate's helper methods. Instead now its just an interface holding method signatures mirroring the java representation of mapped sql statements in MyBatis mapper configuration files. With this changed implementation, everything worked like a charm.
Here is the spring wiring I did to make mybatis-spring work with mapper files. Usually I keep my spring configuration logically separated by keep configuration related to data access in one file and application DAOs go to another. So with this I end up creating four configuration files and one java interface for this project.
- data-access-spring-context.xml: Holding spring configuration defining my data access
- mybatis-config.xml: Standard MyBatis configuration file
- user-dao.xml: MyBatis mapper file. One mapper file for one DAO defined in dao-spring-context.xml
- dao-spring-context.xml: Holding all DAOs used by application
Version of various plugin and framework I used for this little POC...
- Spring 3.0.5
- MyBatis 3.0.2
- MyBatis-Spring 1.0.0-RC2
Let's start visiting each of these files to understand the required configuration...
Well this is pretty much you need to do in order to use MyBatis with Spring. Now just write a test program which loads both spring context as defined above, inject userDAO bean to any of your Java class (typically a business service) and invoke selectUsersmethod.
MyBatis & Spring made data access so simple and using interface as your data access and having implementation as MyBatis mappers, makes data access more cleaner. This is because ideally your data access should only be taking request from business tier to perform some operations like select/insert/update/delete and return the result of such operation back. There should not be any logic. Having your data access as interfaces, takes the any chances of developer mistakenly putting any logic.