springspring-bootspring-datamybatisspring-data-jdbc

spring-data-jdbc integrate with mybatis


I am currently using myBatis for my project, it is good for complex SQL, but I found that I need to create many redundant SQL for basic CRUD. So I come across spring-data-jdbc (here), which is a very nice library (similar to spring-data-jpa but without JPA persistence) to help to generate CRUD SQL statement via method name.

The guide on their official website on how to integrate with myBatis is very vague, I couldn't find any other source which showing how to do that. Basically I am looking for a way to do like below:

@Repository
@Mapper
public interface PersonRepository extends CrudRepository<Person, Long> {

    //via spring-data-jdbc
    List<Person> findAll();
    
    //via spring-data-jdbc
    List<Person> findByFirstName(String name);
    
    //via myBatis, the actual query is in PersonMapper.xml
    List<Person> selectAllRow();
}

As you can see, when I call findAll and findByFirstName, they will be handled by spring-data-jdbc. When I call selectAllRow, it will look for corresponding myBatis mapper file for actual SQL. In this way I can combine two mechanism to handle simple CRUD query and complex query (via myBatis) together.

But above doesn't work, so currently I have to split them into two interface, one for PersonRepository, and another one for PersonMapper, which is not a very nice design.

Anyone has done similar before?


Solution

  • Having two separate interfaces one for repository and another for mybatis mapper is just how mybatis integration in spring-data-jdbc works as of now (version 2.2.1).

    Mapper is just an implemenation detail of the spring data repository and just should not be used by the clients, so it should not be an issue.

    What you want can be probably done but will require quite some work and might not be worth it.

    @Repository annotation instructs spring-data-jdbc to create a proxy implementing PersonRepository with all the machinery of fetching/saving objects to the database.

    @Mapper on the other hand instructs mybatis-spring to create another proxy that will handle queries from the mapping provided in xml or via annotations on the interface method.

    Only one of this proxies can be injected in the places where you are going to use PersonRepository. What you can do is to create your own proxy for PersonRepository that will create both spring-data-jdbc and mybatis proxy and will dispatch calls to them. But the complexity of this solution will be rather high compared to a simple class that delegates to two separate PersonRepository and PersonMapper.

    Update: it seems there is a way to combine mybatis mapper with repository as described in this comment https://github.com/spring-projects/spring-data-jdbc/pull/152#issuecomment-660151636

    This approach uses repository fragments to add mybatis fragment to the repository implementation.