MyBatis is a persistence framework that maps SQL statements to Java methods. Unlike JPA/Hibernate, you write the SQL yourself, giving full control over queries.

MyBatis vs JPA

Aspect MyBatis JPA/Hibernate
SQL control Full (you write SQL) Generated by ORM
Learning curve Lower Higher
Complex queries Excellent Good (JPQL/Criteria)
Object mapping Manual or auto Automatic
Best for SQL-heavy apps, legacy DBs Domain-driven design

Setup

  <dependency>
    <groupId>org.mybatis.spring.boot</groupId>
    <artifactId>mybatis-spring-boot-starter</artifactId>
    <version>3.0.3</version>
</dependency>
  
  mybatis:
  mapper-locations: classpath:mapper/*.xml
  type-aliases-package: com.example.model
  configuration:
    map-underscore-to-camel-case: true
    log-impl: org.apache.ibatis.logging.slf4j.Slf4jImpl
  

Mapper Interface

  @Mapper
public interface UserMapper {
    User findById(@Param("id") Long id);
    List<User> findAll();
    int insert(User user);
    int update(User user);
    int deleteById(@Param("id") Long id);
}
  

XML Mapper

src/main/resources/mapper/UserMapper.xml:

  <?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
    "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.example.mapper.UserMapper">

    <resultMap id="UserResultMap" type="User">
        <id property="id" column="id"/>
        <result property="email" column="email"/>
        <result property="name" column="name"/>
        <result property="createdAt" column="created_at"/>
    </resultMap>

    <select id="findById" resultMap="UserResultMap">
        SELECT id, email, name, created_at FROM users WHERE id = #{id}
    </select>

    <select id="findAll" resultMap="UserResultMap">
        SELECT id, email, name, created_at FROM users ORDER BY id
    </select>

    <insert id="insert" useGeneratedKeys="true" keyProperty="id">
        INSERT INTO users (email, name, created_at)
        VALUES (#{email}, #{name}, #{createdAt})
    </insert>

    <update id="update">
        UPDATE users SET email = #{email}, name = #{name} WHERE id = #{id}
    </update>

    <delete id="deleteById">
        DELETE FROM users WHERE id = #{id}
    </delete>

</mapper>
  

Annotation-Based Mapper

For simple queries, skip XML:

  @Mapper
public interface UserMapper {
    @Select("SELECT * FROM users WHERE id = #{id}")
    User findById(Long id);

    @Insert("INSERT INTO users (email, name) VALUES (#{email}, #{name})")
    @Options(useGeneratedKeys = true, keyProperty = "id")
    int insert(User user);

    @Update("UPDATE users SET name = #{name} WHERE id = #{id}")
    int update(User user);

    @Delete("DELETE FROM users WHERE id = #{id}")
    int deleteById(Long id);
}
  

Using the Mapper

  @Service
public class UserService {
    private final UserMapper userMapper;

    public UserService(UserMapper userMapper) {
        this.userMapper = userMapper;
    }

    public User getUser(Long id) {
        return userMapper.findById(id);
    }

    @Transactional
    public User createUser(CreateUserRequest request) {
        User user = new User(request.getEmail(), request.getName());
        userMapper.insert(user);
        return user;
    }
}
  

SqlSession Lifecycle

MyBatis-Spring manages SqlSession automatically:

  @Mapper interface → MyBatis proxy → SqlSession → JDBC Connection
  

No manual session management needed with Spring Boot integration.

Best Practices

  • Use map-underscore-to-camel-case: true for automatic column mapping
  • Keep complex SQL in XML; use annotations for simple CRUD
  • Use @Param when a method has multiple parameters
  • Enable SQL logging in development for debugging
  • Combine with PageHelper for pagination