MyBatis is a lightweight SQL-mapping framweork that removes most JDBC boiler-plate while still giving full control over SQL. The following walkthrough shows how to integrate it into a Spring Boot project and perform common CRUD operations.
- Project bootstrap and data source configuration
- Create a new Spring Boot project with the
spring-boot-starter-web,mysql-connector-jandmybatis-spring-boot-starterdependencies. - Create the database schema and a matching Java entity. For example:
CREATE TABLE emp (
id INT AUTO_INCREMENT PRIMARY KEY,
username VARCHAR(20) NOT NULL UNIQUE,
password VARCHAR(64) NOT NULL,
full_name VARCHAR(50),
gender TINYINT,
avatar_url VARCHAR(255),
job TINYINT,
hire_date DATE,
dept_id INT,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
);
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Employee {
private Integer id;
private String username;
private String password;
private String fullName;
private Short gender;
private String avatarUrl;
private Short job;
private LocalDate hireDate;
private Integer deptId;
private LocalDateTime createdAt;
private LocalDateTime updatedAt;
}
Add the four mandatory connection parameters to application.properties:
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/demo
spring.datasource.username=demo
spring.datasource.password=demo
To watch the generated SQL in the console, append:
mybatis.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl
- Mapper interfaces and SQL annotations
Define a mapper interface and mark it with @Mapper. Method-level annotations such as @Select, @Insert, @Update and @Delete hold the SQL statements:
@Mapper
public interface EmployeeMapper {
@Select("SELECT * FROM emp")
List<Employee> findAll();
@Select("SELECT * FROM emp WHERE id = #{id}")
Optional<Employee> findById(Integer id);
@Insert("INSERT INTO emp(username, password, full_name, gender, avatar_url, job, hire_date, dept_id) " +
"VALUES(#{username}, #{password}, #{fullName}, #{gender}, #{avatarUrl}, #{job}, #{hireDate}, #{deptId})")
@Options(useGeneratedKeys = true, keyProperty = "id")
int insert(Employee e);
@Update("UPDATE emp SET full_name = #{fullName}, gender = #{gender}, avatar_url = #{avatarUrl}, " +
"job = #{job}, hire_date = #{hireDate}, dept_id = #{deptId}, updated_at = NOW() WHERE id = #{id}")
int update(Employee e);
@Delete("DELETE FROM emp WHERE id = #{id}")
int delete(Integer id);
}
Spring Boot automatically creates a proxy implementation and registers it as a singleton bean, so you can inject the mapper anywhere:
@SpringBootTest
class EmployeeMapperTests {
@Autowired
EmployeeMapper mapper;
@Test
void shouldReturnAllRows() {
List<Employee> list = mapper.findAll();
assertThat(list).isNotEmpty();
}
}
- Connection pooling
Spring Boot ships with HikariCP by default. If you prefer Alibaba’s Druid for its monitoring console, replace the starter:
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>1.2.20</version>
</dependency>
No additional code changes are required.
- Lombok for POJOs
Instead of hand-writing constructors, getters, setters and toString, add Lombok to the classpath and annotate the entity with @Data, @NoArgsConstructor and @AllArgsConstructor as shown above. IntelliJ IDEA already bundles the required plugin.
- XML mapping alternative
If you prefer externalized SQL, place a file named EmployeeMapper.xml under src/main/resources/mapper:
<?xml version="1.0" encoding="UTF-8"?>
<mapper namespace="com.example.demo.mapper.EmployeeMapper">
<select id="findAll" resultType="com.example.demo.entity.Employee">
SELECT * FROM emp
</select>
<select id="findById" resultType="com.example.demo.entity.Employee">
SELECT * FROM emp WHERE id = #{id}
</select>
<insert id="insert" useGeneratedKeys="true" keyProperty="id">
INSERT INTO emp(username, password, full_name, gender, avatar_url, job, hire_date, dept_id)
VALUES(#{username}, #{password}, #{fullName}, #{gender}, #{avatarUrl}, #{job}, #{hireDate}, #{deptId})
</insert>
</mapper>
Enable XML scanning in application.properties:
mybatis.mapper-locations=classpath:mapper/*.xml
With these pieces in place you have a fully working MyBatis layer ready for service and conrtoller integration.