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.
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.StdOutImplTable 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.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
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.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
