Complete Guide to Integrating SpringBoot with MyBatis

This article walks through a full SpringBoot‑MyBatis integration, covering Maven dependencies, application.yml configuration, database schema, entity definition, mapper XML, service layer with transactions and pagination, REST controller endpoints, key features, and common pitfalls.

Java Tech Workshop
Java Tech Workshop
Java Tech Workshop
Complete Guide to Integrating SpringBoot with MyBatis

Dependencies (pom.xml)

<!-- SpringBoot Web -->
<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-web</artifactId>
</dependency>

<!-- MyBatis SpringBoot Starter -->
<dependency>
  <groupId>org.mybatis.spring.boot</groupId>
  <artifactId>mybatis-spring-boot-starter</artifactId>
  <version>2.3.2</version>
</dependency>

<!-- MySQL Driver -->
<dependency>
  <groupId>com.mysql</groupId>
  <artifactId>mysql-connector-j</artifactId>
  <scope>runtime</scope>
</dependency>

<!-- Pagination plugin (PageHelper) -->
<dependency>
  <groupId>com.github.pagehelper</groupId>
  <artifactId>pagehelper-spring-boot-starter</artifactId>
  <version>1.4.7</version>
</dependency>

<!-- Lombok (optional) -->
<dependency>
  <groupId>org.projectlombok</groupId>
  <artifactId>lombok</artifactId>
  <optional>true</optional>
</dependency>

application.yml configuration

server:
  port: 8080

spring:
  datasource:
    url: jdbc:mysql://localhost:3306/testdb?useUnicode=true&characterEncoding=utf-8&serverTimezone=Asia/Shanghai&allowMultiQueries=true
    username: root
    password: 123456
    driver-class-name: com.mysql.cj.jdbc.Driver
  mybatis:
    mapper-locations: classpath:mapper/*.xml
    type-aliases-package: com.demo.entity
    configuration:
      map-underscore-to-camel-case: true
      log-impl: org.apache.ibatis.logging.stdout.StdOutImpl

Table creation SQL (user table)

CREATE TABLE `user` (
  `id` bigint NOT NULL AUTO_INCREMENT COMMENT '主键ID',
  `username` varchar(50) NOT NULL COMMENT '用户名',
  `password` varchar(100) DEFAULT NULL COMMENT '密码',
  `age` int DEFAULT NULL COMMENT '年龄',
  `email` varchar(50) DEFAULT NULL COMMENT '邮箱',
  `create_time` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
  `update_time` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
  `deleted` tinyint DEFAULT 0 COMMENT '逻辑删除 0未删 1已删',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='用户表';

Entity class

package com.demo.entity;

import lombok.Data;
import java.time.LocalDateTime;

@Data
public class User {
    private Long id;
    private String username;
    private String password;
    private Integer age;
    private String email;
    private LocalDateTime createTime;
    private LocalDateTime updateTime;
    private Integer deleted;
}

Mapper interface (data access layer)

package com.demo.mapper;

import com.demo.entity.User;
import org.apache.ibatis.annotations.Param;
import java.util.List;

public interface UserMapper {
    int insert(User user);
    int deleteById(Long id);
    int updateById(User user);
    User selectById(Long id);
    List<User> selectAll();
    List<User> selectByCondition(@Param("username") String username, @Param("age") Integer age);
}

Mapper XML (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.demo.mapper.UserMapper">
  <!-- Insert -->
  <insert id="insert">
    insert into user(username,password,age,email)
    values(#{username},#{password},#{age},#{email})
  </insert>

  <!-- Delete -->
  <delete id="deleteById">
    delete from user where id=#{id}
  </delete>

  <!-- Update -->
  <update id="updateById">
    update user set username=#{username},age=#{age},email=#{email} where id=#{id}
  </update>

  <!-- Select by ID (non‑deleted) -->
  <select id="selectById" resultType="User">
    select * from user where id=#{id} and deleted=0
  </select>

  <!-- Select all (non‑deleted) -->
  <select id="selectAll" resultType="User">
    select * from user where deleted=0
  </select>

  <!-- Dynamic multi‑condition query -->
  <select id="selectByCondition" resultType="User">
    select * from user
    <where>
      deleted=0
      <if test="username != null and username != ''">
        and username like concat('%',#{username},'%')
      </if>
      <if test="age != null">
        and age = #{age}
      </if>
    </where>
  </select>
</mapper>

Application entry (Mapper scan)

@SpringBootApplication
@MapperScan("com.demo.mapper")
public class DemoApplication {
    public static void main(String[] args) {
        SpringApplication.run(DemoApplication.class, args);
    }
}

Service layer

UserService interface

package com.demo.service;

import com.demo.entity.User;
import com.github.pagehelper.PageInfo;
import java.util.List;

public interface UserService {
    boolean add(User user);
    boolean delete(Long id);
    boolean update(User user);
    User getById(Long id);
    List<User> list();
    List<User> search(String username, Integer age);
    PageInfo<User> page(Integer pageNum, Integer pageSize);
}

UserServiceImpl implementation

package com.demo.service.impl;

import com.demo.entity.User;
import com.demo.mapper.UserMapper;
import com.demo.service.UserService;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import javax.annotation.Resource;
import java.util.List;

@Service
public class UserServiceImpl implements UserService {
    @Resource
    private UserMapper userMapper;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean add(User user) {
        return userMapper.insert(user) > 0;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean delete(Long id) {
        return userMapper.deleteById(id) > 0;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean update(User user) {
        return userMapper.updateById(user) > 0;
    }

    @Override
    public User getById(Long id) {
        return userMapper.selectById(id);
    }

    @Override
    public List<User> list() {
        return userMapper.selectAll();
    }

    @Override
    public List<User> search(String username, Integer age) {
        return userMapper.selectByCondition(username, age);
    }

    @Override
    public PageInfo<User> page(Integer pageNum, Integer pageSize) {
        PageHelper.startPage(pageNum, pageSize);
        List<User> list = userMapper.selectAll();
        return new PageInfo<>(list);
    }
}

Controller layer (REST API)

package com.demo.controller;

import com.demo.common.Result;
import com.demo.entity.User;
import com.demo.service.UserService;
import com.github.pagehelper.PageInfo;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;

@RestController
@RequestMapping("/user")
public class UserController {
    @Resource
    private UserService userService;

    @PostMapping("/add")
    public Result add(@RequestBody User user) {
        userService.add(user);
        return Result.success("新增成功");
    }

    @DeleteMapping("/delete/{id}")
    public Result delete(@PathVariable Long id) {
        userService.delete(id);
        return Result.success("删除成功");
    }

    @PutMapping("/update")
    public Result update(@RequestBody User user) {
        userService.update(user);
        return Result.success("修改成功");
    }

    @GetMapping("/detail/{id}")
    public Result detail(@PathVariable Long id) {
        return Result.success(userService.getById(id));
    }

    @GetMapping("/list")
    public Result list() {
        return Result.success(userService.list());
    }

    @GetMapping("/search")
    public Result search(@RequestParam(required = false) String username,
                         @RequestParam(required = false) Integer age) {
        return Result.success(userService.search(username, age));
    }

    @GetMapping("/page")
    public Result page(@RequestParam(defaultValue = "1") Integer pageNum,
                       @RequestParam(defaultValue = "10") Integer pageSize) {
        PageInfo<User> page = userService.page(pageNum, pageSize);
        return Result.success(page);
    }
}

Key features

Pagination (PageHelper) – call PageHelper.startPage immediately before the query; MyBatis automatically appends LIMIT and returns a PageInfo containing total count, total pages, current page, and data list.

Dynamic SQL – <if> and <where> tags enable multi‑condition searches without manual SQL concatenation.

Transaction control – methods annotated with @Transactional roll back on any exception.

Underscore‑to‑camel‑case mapping – enabled via map-underscore-to-camel-case: true, converting columns such as create_time to createTime.

Common pitfalls

Mapper injection failure – the main application class must include @MapperScan("com.demo.mapper").

XML binding exception – the namespace attribute in the mapper XML must exactly match the fully qualified mapper interface name.

Pagination not effective – ensure PageHelper.startPage is placed directly before the query method.

SQL errors in XML – characters such as & and < must be escaped.

Field mapping issues – enable underscore‑to‑camel‑case conversion to map columns like create_time to createTime.

Multiple parameters – annotate each parameter with @Param; otherwise MyBatis cannot bind them.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

JavaTransactionMyBatisPaginationSpringBootCRUD
Java Tech Workshop
Written by

Java Tech Workshop

Focused on Java backend technologies, sharing fundamentals, multithreading, JVM, the Spring ecosystem, microservices, distributed systems, high concurrency, source‑code analysis, and practical experience. Continuously delivers high‑quality original content, interview guides, and learning roadmaps to help Java developers progress from beginner to advanced, enhancing technical skills and core competitiveness.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.