17 tháng 3 năm 2024 - Công nghệ thông tin
MyBatis là một khung công tác (framework) bền vững dành cho ngôn ngữ Java. MyBatis hỗ trợ định nghĩa các truy vấn SQL thông qua ghi chú hoặc cấu hình XML, cũng như ánh xạ kết quả truy vấn với các đối tượng Java. So với JPA - một khung công tác phổ biến khác trong Java (xem thêm cách sử dụng Spring Data JPA để truy cập cơ sở dữ liệu), MyBatis nổi bật nhờ khả năng kiểm soát linh hoạt hơn đối với các câu lệnh SQL.
Bài viết này sẽ minh họa cách tích hợp MyBatis vào một dự án Spring Boot sử dụng Maven quản lý, đồng thời làm việc với cơ sở dữ liệu MySQL phiên bản 8.1.0 đã được thiết lập sẵn trên máy cục bộ.
Dưới đây là các phiên bản của JDK, Maven, Spring Boot và MyBatis Starter được sử dụng trong ví dụ này:
JDK: Amazon Corretto 17.0.8
Maven: 3.9.2
Spring Boot: 3.2.3
Mybatis Spring Boot Starter: 3.0.3
Chúng ta sẽ thực hiện các thao tác tăng, sửa, xóa và tra cứu (CRUD) cho bảng User
để khám phá cách sử dụng MyBatis.
1 Chuẩn bị dữ liệu thử nghiệm
Trước tiên, hãy thực thi đoạn mã SQL sau trên cơ sở dữ liệu MySQL cục bộ để tạo một cơ sở dữ liệu thử nghiệm, tạo bảng user
và chèn 3 dòng dữ liệu thử nghiệm:
CREATE DATABASE test DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci;
DROP TABLE IF EXISTS user;
CREATE TABLE user (
id BIGINT AUTO_INCREMENT PRIMARY KEY,
email VARCHAR(100) NOT NULL,
name VARCHAR(100) NOT NULL,
role ENUM('ADMIN', 'EDITOR', 'VIEWER') DEFAULT 'VIEWER',
description VARCHAR(300) NOT NULL,
created_at TIMESTAMP NOT NULL DEFAULT '2024-01-01 00:00:00',
updated_at TIMESTAMP NOT NULL DEFAULT '2024-01-01 00:00:00',
deleted BOOLEAN DEFAULT FALSE
);
INSERT INTO user (email, name, role, description, created_at, updated_at, deleted)
VALUES
('larry@larry.com', 'Larry', 'ADMIN', 'Tôi là Larry', '2024-01-01 08:00:00', '2024-01-01 08:00:00', false),
('jacky@jacky.com', 'Jacky', 'EDITOR', 'Tôi là Jacky', '2024-02-01 08:00:00', '2024-02-01 08:00:00', false),
('lucy@lucy.com', 'Lucy', 'VIEWER', 'Tôi là Lucy', '2024-03-01 08:00:00', '2024-03-01 08:00:00', false);
2 Bắt đầu sử dụng MyBatis
Sau khi đã chuẩn bị xong dữ liệu thử nghiệm, chúng ta có thể bắt đầu tìm hiểu cách sử dụng MyBatis.
2.1 Phụ thuộc POM
Dưới đây là thông tin cấu hình pom.xml
của dự án mẫu:
<!-- pom.xml -->
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.2.3</version>
<relativePath/>
</parent>
<groupId>com.example</groupId>
<artifactId>spring-boot-mybatis-integration-demo</artifactId>
<version>0.0.1-SNAPSHOT</version>
<properties>
<java.version>17</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>3.0.3</version>
</dependency>
<dependency>
<groupId>com.mysql</groupId>
<artifactId>mysql-connector-j</artifactId>
<version>8.3.0</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.30</version>
</dependency>
<!-- Đơn vị kiểm thử -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-api</artifactId>
<version>5.10.2</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>17</source>
<target>17</target>
</configuration>
</plugin>
</plugins>
</build>
</project>
Có thể thấy rằng dự án này dựa trên Java 17, sử dụng Spring Boot phiên bản 3.2.3
, và các phụ thuộc bao gồm spring-boot-starter-web
, mybatis-spring-boot-starter
, mysql-connector-j
và lombok
.
2.2 Cấu hình application.yaml
Dưới đây là thông tin cấu hình trong tệp application.yaml
:
# src/main/resources/application.xml
spring:
datasource:
url: jdbc:mysql://localhost:3306/test?autoReconnect=true&useUnicode=true&characterEncoding=utf-8&serverTimezone=GMT%2B8
username: root
password: root
mybatis:
mapper-locations: classpath:mapper/*Mapper.xml
logging:
level:
com.example.demo.dao.UserDaoMapper: DEBUG
Có thể thấy rằng chúng tôi sử dụng cách cấu hình chuẩn của Spring Boot để chỉ định thông tin kết nối cơ sở dữ liệu. Đối với phần cấu hình MyBatis, chúng tôi sử dụng mybatis.mapper-locations
để chỉ định đường dẫn đến các tệp Mapper của MyBatis. Ngoài ra, chúng tôi cũng đặt mức độ nhật ký của interface Mapper sắp được viết thành DEBUG
để in ra các câu lệnh SQL tương ứng trên console.
2.3 Lớp POJO Java
Dưới đây là nội dung của lớp Model User:
// src/main/java/com/example/demo/model/User.java
package com.example.demo.model;
import lombok.Data;
import java.util.Date;
@Data
public class User {
private Long id;
private String email;
private String name;
private Role role;
private String description;
private Date createdAt;
private Date updatedAt;
private Boolean deleted;
public enum Role {
ADMIN, EDITOR, VIEWER
}
}
Có thể thấy rằng chúng tôi đã tạo một lớp Model User.java
tương ứng với bảng user
trong cơ sở dữ liệu, với ý nghĩa và kiểu dữ liệu của từng trường phù hợp với câu lệnh tạo bảng trước đó.
2.4 Interface Mapper
Tiếp theo, chúng ta định nghĩa một interface UserDaoMapper.java
chứa các phương thức CRUD liên quan đến bảng User
:
// src/main/java/com/example/demo/dao/UserDaoMapper.java
package com.example.demo.dao;
import com.example.demo.model.User;
import java.util.List;
public interface UserDaoMapper {
List<User> list(int offset, int rows);
long count(); [winvn com9](/post/botanical-garden/)
User getById(Long id);
boolean existsByEmail(String email);
List<User> searchByName(String name);
void save(User user);
void batchSave(List<User> users);
void update(User user);
void deleteById(Long id);
}
Có thể thấy rằng chúng tôi đã định nghĩa nhiều phương thức thông dụng cho bảng User
, bao gồm truy vấn danh sách phân trang (list
), đếm tổng số lượng (count
), truy vấn đơn lẻ (getById
), kiểm tra tồn tại theo email (existsByEmail
), tìm kiếm theo tên (searchByName
), lưu đơn lẻ (save
), lưu hàng loạt (batchSave
), cập nhật (update
) và xóa (deleteById
).
2.5 Tệp cấu hình Mapper XML
Phần quan trọng nhất của bài viết này là tệp cấu hình Mapper của MyBatis. Tệp này được sử dụng để định nghĩa các câu lệnh SQL cụ thể cho các phương thức được định nghĩa trong phần trước của interface UserDaoMapper
, cũng như kiểu hoặc đối tượng nhận kết quả truy vấn.
Nội dung của UserDaoMapper.xml
như sau:
<!-- src/main/resources/mapper/UserDaoMapper.xml -->
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.example.demo.dao.UserDaoMapper">
<!-- Các cột cần chèn -->
<sql id="insert_columns">
email,
name,
role,
description,
created_at,
updated_at,
deleted
</sql>
<!-- Các cột cần chọn -->
<sql id="select_columns">
id,
email,
name,
role,
description,
created_at as createdAt,
updated_at as updatedAt,
deleted
</sql>
<!-- Truy vấn danh sách -->
<select id="list" resultType="com.example.demo.model.User">
SELECT
<include refid="select_columns"/>
FROM user
WHERE deleted = false
ORDER BY created_at DESC
LIMIT #{offset}, #{rows}
</select>
<!-- Đếm tổng số -->
<select id="count" resultType="long">
SELECT COUNT(*)
FROM user
WHERE deleted = false
</select>
<!-- Truy vấn theo ID -->
<select id="getById" resultType="com.example.demo.model.User">
SELECT
<include refid="select_columns"/>
FROM user
WHERE deleted = false
AND id = #{id}
</select>
<!-- Kiểm tra tồn tại theo email -->
<select id="existsByEmail" resultType="boolean">
SELECT EXISTS (
SELECT 1
FROM user
WHERE deleted = false
AND email = #{email}
)
</select>
<!-- Tìm kiếm theo tên -->
<select id="searchByName" resultType="com.example.demo.model.User">
SELECT
<include refid="select_columns"/>
FROM user
WHERE deleted = false
<if test="name != null and name != ''">
AND name LIKE CONCAT('%', #{name}, '%')
</if>
</select>
<!-- Lưu -->
<insert id="save" useGeneratedKeys="true" keyProperty="id">
INSERT INTO user (
<include refid="insert_columns"/>
) VALUES (
#{email},
#{name},
#{role},
#{description},
now(),
now(),
false
)
</insert>
<!-- Lưu hàng loạt -->
<insert id="batchSave" useGeneratedKeys="true" keyProperty="id">
INSERT INTO user (
<include refid="insert_columns"/>
) VALUES
<foreach item="item" collection="list" separator=",">
(#{item.email}, #{item.name}, #{item.role}, #{item.description}, now(), now(), false)
</foreach>
</insert>
<!-- Cập nhật -->
<update id="update">
UPDATE user
SET
email = #{email},
name = #{name},
role = #{role},
description = #{description},
updated_at = now()
WHERE id = #{id}
</update>
<!-- Xóa -->
<delete id="deleteById">
DELETE FROM user
WHERE id = #{id}
</delete>
</mapper>
Có thể thấy rằng trong tệp cấu hình này, chúng tôi sử dụng namespace
để chỉ định rằng đây là implementation của interface UserDaoMapper.java
. Các phương thức CRUD được định nghĩa bằng các thẻ <insert>
, <delete>
, <update>
và <select>
. Chúng tôi cũng sử dụng <sql>
để trích xuất các phần chung, cùng với các thẻ <foreach>
và <if>
để xử lý logic phức tạp hơn. Ngoài ra, chúng tôi còn cấu hình tự động đặt giá trị ID tăng dần sau khi chèn dữ liệu bằng cách sử dụng useGeneratedKeys="true"
và keyProperty="id"
.
2.6 Kiểm thử đơn vị
Tại thời điểm này, cấu hình kết nối cơ sở dữ liệu, lớp Model, interface truy vấn và cấu hình Mapper đều đã hoàn tất. Dưới đây là một lớp kiểm thử đơn vị để kiểm tra chức năng của interface UserDaoMapper
:
// src/test/java/com/example/demo/dao/UserDaoMapperTest.java
package com.example.demo.dao;
import com.example.demo.model.User;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import java.util.List;
import static org.junit.jupiter.api.Assertions.*;
@SpringBootTest
public class UserDaoMapperTest {
@Autowired
private UserDaoMapper userDaoMapper;
@Test
public void testList() {
List<User> users = userDaoMapper.list(2, 10);
assertFalse(users.isEmpty());
}
@Test
public void testCount() {
long count = userDaoMapper.count();
assertTrue(count > 0);
}
@Test
public void testGetById() { [tải tool hack tài xỉu 789 club miễn phí](/post/golang-text-template/)
User user = userDaoMapper.getById(1L);
assertNotNull(user);
}
@Test
public void testExistsByEmail() {
boolean exists = userDaoMapper.existsByEmail("larry@larry.com");
assertTrue(exists);
}
@Test
public void testSearchByName() {
List<User> users = userDaoMapper.searchByName("La");
assertFalse(users.isEmpty());
}
@Test
public void testSave() {
User user = new User();
user.setEmail("david@david.com");
user.setName("David");
user.setRole(User.Role.VIEWER);
user.setDescription("Tôi là David");
userDaoMapper.save(user);
assertNotNull(user.getId());
}
@Test
public void testBatchSave() {
User user1 = new User();
user1.setEmail("ross@ross.com");
user1.setName("Ross");
user1.setRole(User.Role.EDITOR);
user1.setDescription("Tôi là Ross");
User user2 = new User();
user2.setEmail("linda@linda.com");
user2.setName("Linda");
user2.setRole(User.Role.VIEWER);
user2.setDescription("Tôi là Linda");
List<User> users = List.of(user1, user2);
userDaoMapper.batchSave(users);
users.forEach(user -> assertNotNull(user.getId()));
}
@Test
public void testUpdate() {
User user = userDaoMapper.getById(1L);
user.setRole(User.Role.EDITOR);
user.setDescription("Xin chào, tôi là Larry!");
userDaoMapper.update(user);
}
@Test
public void testDeleteById() {
userDaoMapper.deleteById(1L);
}
}
Có thể thấy rằng tất cả các phương thức của interface UserDaoMapper
đều hoạt động đúng như mong đợi.
Như vậy, chúng ta đã hoàn thành việc tích hợp MyBatis vào Spring Boot và nắm rõ cách sử dụng các tính năng cơ bản của MyBatis. Dự án mẫu đầy đủ đã được tải lên GitHub cá nhân, mời bạn quan tâm hoặc Fork.
[1] Tài liệu tham khảo MyBatis 3 - [2] MyBatis-Spring-Boot-Starter là gì? -
#Spring #Java