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 the sqlSessionTemplate 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
- UserDAO.java
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...
- data-access-spring-context.xml:
For simplicity, I've not included the transaction manager, advice point cut etc in this. So here, main point of interest is how the sql session factory and sql session template is configured which actually wires MyBatis configuration to Spring data accessclasspath:jdbc.properties ${DataSource.JndiName.DS} false
- mybatis-config.xml:
This is a standard MyBatis configuration file, holding all the mappers of the applications.
- user-dao.xml
Here I've defined a SQL queries required my my User DAO. User DAO is wired to spring data access and mybatis in my DAO spring context i.e. dao-spring-context.xml
- dao-spring-context.xml:
Notice that the fully qualified interface name defined as mapperInterface serves as the namespace for the mapper in user-dao.xml.
- UserDAO.java:
package com.jak.sandbox.biz.dao; import java.util.List; import com.jak.sandbox.shared.dto.model.User; public interface UserDAO { List<User> selectUsers(); }
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 selectUsers method.
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.
Cheers !!!
- Jay


can u write small injection sample for this post?
ReplyDeletetutorial is realy good and simple
Injection sample? can you elaborate?
ReplyDeleteWith Spring moving to Annotations, how could this same sample be written using Annotations?
ReplyDeleteYou can refer to this link for annotation examples
ReplyDeletehttp://www.jpadbf.org/2010/09/mybatis3-spring3-integration-using-mybatis3-new-features/
Does this example really work? applicationContext appears incorrect:
ReplyDeleteclass="org.mybatis.spring.mapper.MapperFactoryBean"
David, yes it does work. am using Spring 3.0.5, mybatis 3 and mybatis-spring 1.0 RC3. Hope this helps.
ReplyDeleteDavid this sample uses RC2 where the MapperFactoryBean was in org.mybatis.spring package but now it is in org.mybatis.spring.mapper. It good be a good idea to update this article.
ReplyDeleteApart from that it seems that there is a xml syntax error here:
it should be:
I see, I'm looking at the current mybatis-spring and the package name has changed.
ReplyDeleteGuys, Sorry for the typo. Yes its RC2 and not RC3. I'll update the article to include the version which have been used for the sample code mentioned.
ReplyDeletegreat tutorial, i was going through the MyBatis docs but couldn't find a simple example of how to use XML files in stead of annotations.
ReplyDeleteThis worked great, Thanks!
you have made it more complicated,,
ReplyDeleteFor something whos reading this guide.
ReplyDeleteJust finished converting spring2ibatis2->spring3mybatis3 myself. The "org.mybatis.spring.support.SqlSessionDaoSupport " class's checkDaoConfig assert is very valid, all you need is add "" in all your Dao beans. The other post omitted that, so you getting that error.
There's no need for using Dao xmls. Sometime you do need to do something extra on the Dao before returning results back to your say.."UserManager"
hey jay can you please provide the class containing main method..???
ReplyDeleteAnuj, I'm not sure if I still have that project with me, as I just did it as POC. But what exactly you want from that main class. It would have only the spring container initialization.
ReplyDeletejay the thing is when i try to run this snippets inside my code they are givin error for bean creation.
ReplyDeleteerror is that no init() method found for sqlSessionFactory bean.
and the problem is i am totally new to SPRING + MYBATIS and i need to migrate my simple JAVA based client server program to it..
so if u can help ...
Anuj, if you can send the exception stacktrace then debugging can be easier...
ReplyDeleteHello Jay,
ReplyDeleteI am facing problem in writing to db via myBatis in my Spring3 application... I get a null exception error as soon as the DAO object is accessed. Can I share the codebase with you, it is still small, w/o much functionality?
Vandana, sure you can, not sure how much I'd be of help, but will try. Paste the troubling code over here and will have a look
ReplyDeleteThanks a ton Jay for the willingness to help.
ReplyDeleteI am pasting some relevant parts of some files below, please let me know if more details are required, or if I can send you the complete codebase zip:
==================================================
/WEB-INF/web.xml
....
org.springframework.web.context.ContextLoaderListener
......
contextConfigLocation
/WEB-INF/applicationContext.xml
....
==================================================
/WEB-INF/applicationContext.xml
....
......
==================================================
/WEB-INF/mybatis-config.xml
----
.....
NOTE: I have tried with moving the mybatis.xml file in the src folder and also here in the WEB-INF folder. I have also tried with adding Envirnment tag in the mybatis file.
==================================================
/src/com/abc/xyz/service/UserService.java
Problem is when UserMapper is accessed in below code, it gives a null exception error. Tried the following variations:
=========================================
Variation1
@Autowired
private UserMapper userMapper;
public void insertUser(User user) {
userMapper.insertUser(user);
}
=================================
Variation 2
@Autowired
private UserMapper userMapper;
private SqlSessionFactory sqlSessionFactory;
//constructor
public UserService(){
sqlSessionFactory = MyBatisConnectionFactory.getSqlSessionFactory();
}
public void insertUser(User user) {
SqlSession session = sqlSessionFactory.openSession();
try{
session.insert("User.insertUser",user);
/*Also tried this: userMapper = session.getMapper(UserMapper.class);
userMapper.insertUser(user); */
}
==============================================
All I get is a NullException Error when userMApper is accessed.
Vandana, this seems to be more of spring wiring problem then myBatis. Have you checked if your spring application context fires up properly, like all your beans are getting instantiated properly and wiring is happening? Either your application contexts is not getting initialized or there is some issue with your userMapper bean wiring.
ReplyDeleteCan I have copy zip file or war link for these code?
ReplyDeleteThanks
Sorry I can not find the project, it was almost a year back and I just did as to test something.
ReplyDeleteuse the below link.I tried and it works correctly
ReplyDeletehttp://www.jpadbf.org/2010/09/mybatis3-spring3-integration-using-mybatis3-new-features/