前言 🌟
在掌握了 MyBatis 的基本配置与环境搭建之后,接下来的重点便是深入理解其核心功能------CRUD 操作(增删改查)。💻
数据库操作是任何应用开发中不可或缺的一环,而 MyBatis 正是通过灵活的 SQL 映射机制,极大地简化了这些操作的实现过程。本篇将围绕最常见的数据库基本操作展开,带你从传统 JDBC 的冗杂代码,迈向 MyBatis 优雅高效的开发方式。
我们将通过实际案例,结合注解与 XML 两种方式,逐一讲解如何使用 MyBatis 实现:
-
新增数据 🆕
-
删除数据 ❌
-
更新数据 🔁
-
查询数据 🔍
同时,还将分析每种实现方式的优劣,帮助你根据项目需求做出合理的选择。
无论你是初学者,还是希望进一步深入理解 MyBatis 的开发者,都能从这篇内容中收获实用技巧与开发灵感。🚀

基本操作回顾 🔁
MyBatis 的核心用途之一就是对数据库的 增删改查(CRUD) 操作进行简化和优化。在传统 JDBC 中,每次都需要写大量重复性的代码来完成这些操作,而在 MyBatis 中,你可以通过 注解 或 XML 映射 两种方式优雅地完成同样的工作。
下面我们分别回顾这四种操作的基本语法,并通过两个方式(注解和 XML)进行展示。📘
1. 增、删、改、查的基本语法和实现方式 🔄
在数据库操作中,通常有四种基本操作:增(Insert)💾、删(Delete)🗑️、改(Update)🔧和查(Select)🔍。每种操作的基本语法如下:
-
增(Insert) 🆕
INSERT INTO table_name (column1, column2, column3, ...) VALUES (value1, value2, value3, ...);
-
删(Delete) ❌
DELETE FROM table_name WHERE condition;
-
改(Update) 🔄
UPDATE table_name SET column1 = value1, column2 = value2, ... WHERE condition;
-
查(Select) 👀
SELECT column1, column2, column3, ... FROM table_name WHERE condition ORDER BY column1;
这些语法是进行数据库操作的基础,通常会结合特定的框架和技术来简化实现。🚀
2. SQL映射的定义(注解与XML方式) 📝
在 Java 中,使用 MyBatis 框架时,通常需要将 SQL 操作映射到 Java 方法。MyBatis 提供了两种方式来定义这些 SQL 映射:注解方式 和XML方式。
注解方式 💡
在 MyBatis 中,你可以通过注解在接口方法上定义 SQL 语句。以下是常用的注解:
-
@Insert ✍️:用于插入数据。
-
@Update 🔄:用于更新数据。
-
@Delete 🗑️:用于删除数据。
-
@Select 🔍:用于查询数据。
示例:
public interface UserMapper {
@Insert("INSERT INTO users (name, age) VALUES (#{name}, #{age})")
void insertUser(User user);
@Select("SELECT * FROM users WHERE id = #{id}")
User selectUserById(int id);
@Update("UPDATE users SET name = #{name}, age = #{age} WHERE id = #{id}")
void updateUser(User user);
@Delete("DELETE FROM users WHERE id = #{id}")
void deleteUser(int id);
}
XML方式 📝
在 XML 映射文件中,SQL 语句被定义在 <mapper>
标签中。每个 SQL 操作通过不同的标签(如 <insert>
, <select>
, <update>
, <delete>
)进行映射。
示例:
UserMapper.xml
<mapper namespace="com.example.UserMapper">
<insert id="insertUser" parameterType="User">
INSERT INTO users (name, age)
VALUES (#{name}, #{age})
</insert>
<select id="selectUserById" resultType="User">
SELECT * FROM users WHERE id = #{id}
</select>
<update id="updateUser" parameterType="User">
UPDATE users
SET name = #{name}, age = #{age}
WHERE id = #{id}
</update>
<delete id="deleteUser" parameterType="int">
DELETE FROM users WHERE id = #{id}
</delete>
</mapper>
🧩 注解 vs XML 映射方式对比
方式 | 优点 🌟 | 缺点 ⚠️ | 适用场景 📌 |
---|---|---|---|
注解方式 | 简洁直观,代码集中在一处 | 不适合复杂 SQL 语句 | 简单的增删改查 |
XML方式 | 结构清晰,适合复杂 SQL & 动态 SQL | 映射文件和接口分离,维护略复杂 | SQL 语句复杂、需灵活配置时 |
选择注解还是 XML? 🤔
-
注解方式 ✅:简洁,适合小型项目或简单的 SQL 操作。
-
XML方式 📂:更灵活,适合复杂查询,且可以分离 SQL 和 Java 代码,提高可维护性。
一般来说,如果项目较小,且 SQL 操作较为简单,可以使用注解;而如果 SQL 语句复杂,或者希望保持 Java 代码与 SQL 的分离,XML 方式更加合适。🔧
在 MyBatis 中,插入操作(Insert)可以通过注解或 XML 配置两种方式实现。此外,利用 @Options
注解或 XML 配置中的 useGeneratedKeys
属性,可以实现插入数据后返回自增主键的功能。以下是对这两种方式的详细介绍和示例代码。
🆕 增操作(Insert)
在 MyBatis 中,执行插入操作主要有两种方式:使用 @Insert
注解 和 使用 XML 映射中的 <insert>
标签。两者都可以完成插入任务,但在处理返回主键时,写法稍有不同。
@Insert 注解与 XML 中 <insert>
标签的差异
1. 使用 @Insert 注解
@Insert
注解用于在 Mapper 接口中直接编写 SQL 语句,适用于简单的插入操作。例如:
@Insert("INSERT INTO users(name, age) VALUES(#{name}, #{age})")
int addUser(User user);
这种方式简洁明了,便于快速开发。然而,当 SQL 语句较为复杂或需要动态构建时,注解方式的可读性和维护性会降低。
2. 使用 XML 中的 <insert>
标签
在 XML 配置中,使用 <insert>
标签定义插入操作,适用于复杂的 SQL 语句和动态 SQL 的构建。例如:
<insert id="addUser" parameterType="User">
INSERT INTO users(name, age)
VALUES(#{name}, #{age})
</insert>
XML 配置方式提供了更高的灵活性和可维护性,特别是在处理复杂逻辑和动态 SQL 时更为合适。
利用 Options 配置返回自增主键
在插入数据后获取数据库生成的自增主键,可以通过以下两种方式实现:
1. 注解方式
在使用 @Insert
注解的同时,结合 @Options
注解配置返回主键的相关属性。例如:
@Insert("INSERT INTO users(name, age) VALUES(#{name}, #{age})")
@Options(useGeneratedKeys = true, keyProperty = "id", keyColumn = "id")
int addUser(User user);
-
useGeneratedKeys = true
:表示使用数据库自动生成的主键。 -
keyProperty = "id"
:指定将生成的主键值赋给User
对象的id
属性。 -
keyColumn = "id"
:指定数据库表中的主键列名。
这样配置后,插入操作执行完毕后,User
对象的 id
属性将自动填充为数据库生成的主键值。
2. XML 配置方式
在 XML 中的 <insert>
标签中设置相关属性,实现相同的功能。例如:
<insert id="addUser" parameterType="User" useGeneratedKeys="true" keyProperty="id" keyColumn="id">
INSERT INTO users(name, age)
VALUES(#{name}, #{age})
</insert>
配置说明与注解方式相同,执行插入操作后,User
对象的 id
属性将被自动赋值为生成的主键。
示例代码
以下是一个完整的示例,展示如何使用注解方式插入数据并返回自增主键:
public interface UserMapper {
@Insert("INSERT INTO users(name, age) VALUES(#{name}, #{age})")
@Options(useGeneratedKeys = true, keyProperty = "id", keyColumn = "id")
int addUser(User user);
}
在调用 addUser
方法后,User
对象的 id
属性将被自动填充为数据库生成的主键值。
如果使用 XML 配置方式,Mapper 接口方法可以简化为:
int addUser(User user);
对应的 XML 配置如下:
<insert id="addUser" parameterType="User" useGeneratedKeys="true" keyProperty="id" keyColumn="id">
INSERT INTO users(name, age)
VALUES(#{name}, #{age})
</insert>
这样配置后,同样可以在插入数据后自动获取并设置主键值。
❌ 删操作(Delete) & 🔁 改操作(Update)
在 MyBatis 中,删除(Delete)和更新(Update)操作可以通过注解或 XML 配置两种方式实现。在使用这些操作时,参数传递和绑定是关键,尤其是在方法参数较多或参数名与 SQL 中不一致时,合理使用 @Param
注解至关重要,除了掌握基本语法外,参数传递与绑定方式 是非常关键的一环,尤其是当方法中传入多个参数或参数名与 SQL 占位符不一致时,可能导致绑定失败或运行报错。
一.🧠 参数传递注意点
-
单个参数:
-
当方法只接受一个参数时,MyBatis 可以自动识别参数名,无需使用
@Param
注解。 -
例如:
@Delete("DELETE FROM users WHERE id = #{id}") int deleteUserById(int id);
-
-
多个参数:
-
当方法接受多个参数时,MyBatis 默认将参数命名为
param1
、param2
等,可能导致 SQL 中的参数名与方法参数不一致。 -
为避免这种情况,建议使用
@Param
注解为每个参数指定名称。 -
例如:
@Update("UPDATE users SET name = #{name} WHERE id = #{id}") int updateUser(@Param("id") int id, @Param("name") String name);
-
-
使用 JavaBean 作为参数:
-
如果方法参数是一个 JavaBean 对象,MyBatis 会根据对象的属性名进行参数绑定,无需使用
@Param
注解。 -
例如:
@Update("UPDATE users SET name = #{name}, age = #{age} WHERE id = #{id}") int updateUser(User user);
-
-
使用 Map 作为参数:
-
当方法参数为 Map 类型时,SQL 中的参数名应与 Map 的键一致。
-
例如:
@Delete("DELETE FROM users WHERE id = #{userId}") int deleteUser(Map<String, Object> params);
-
二、注解方式实现删除和更新操作
1. 删除操作
-
单个参数:
@Delete("DELETE FROM users WHERE id = #{id}") int deleteUserById(int id);
-
多个参数(使用 @Param):
@Delete("DELETE FROM users WHERE id = #{id} AND status = #{status}") int deleteUser(@Param("id") int id, @Param("status") String status);
2. 更新操作
-
使用 JavaBean 作为参数:
@Update("UPDATE users SET name = #{name}, age = #{age} WHERE id = #{id}") int updateUser(User user);
-
多个参数(使用 @Param):
@Update("UPDATE users SET name = #{name} WHERE id = #{id}") int updateUser(@Param("id") int id, @Param("name") String name);
三、XML 方式实现删除和更新操作
1. 删除操作
<delete id="deleteUserById" parameterType="int">
DELETE FROM users WHERE id = #{id}
</delete>
2. 更新操作
-
使用 JavaBean 作为参数:
<update id="updateUser" parameterType="User"> UPDATE users SET name = #{name}, age = #{age} WHERE id = #{id} </update>
-
多个参数(使用 @Param):
<update id="updateUser" parameterType="map"> UPDATE users SET name = #{name} WHERE id = #{id} </update>
四、使用 @Param 注解的最佳实践
-
多个参数时使用 @Param :当方法有多个参数时,使用
@Param
注解为每个参数指定名称,以确保 SQL 中的参数名与方法参数一致。 -
**避免使用 {}** :在 SQL 中使用 `{}
会直接拼接字符串,可能导致 SQL 注入风险。建议使用
#{}` 进行参数绑定。 -
参数名与 SQL 中一致 :确保方法参数名与 SQL 中的参数名一致,或通过
@Param
注解进行明确绑定。
🔍 查询操作(Select)
在 MyBatis 中,查询是使用最频繁、最关键的操作之一。无论是查询单条记录还是查询列表,MyBatis 提供了丰富的方式来处理返回单个对象和列表的场景,同时也支持自动映射(result mapping)的机制,以便把数据库查询结果转换为 Java 对象。
但自动映射不是"万能"的,字段名不一致时容易出现问题,本节将详解如何解决这些常见坑点 👇
一、查询单个对象与列表的差异
-
单个对象查询
通常使用方法返回类型为对象(如
User
)的查询接口。当查询结果只返回一行数据时,这样能直接将返回值自动映射到对应的 Java 对象。例如:@Select("SELECT id, name, age FROM users WHERE id = #{id}") User getUserById(int id);
如果查询结果为空或多条记录,则可能会导致异常,此时需要保证查询条件唯一。
-
列表查询
当查询的结果可能包含多行数据时,接口返回值一般为
List<User>
。MyBatis 会遍历每一行数据并调用映射规则将每行数据封装成一个 Java 对象,最终返回一个列表。例如:@Select("SELECT id, name, age FROM users") List<User> getAllUsers();
二、自动映射原理与字段映射问题
MyBatis 能自动将数据库查询的结果映射到 Java 对象中,但前提是 SQL 返回的列名和 Java 对象的属性名需要保持一致。实际应用中常遇到如下问题及相应解决方法:
1. 起别名(Alias)
如果数据库表中的列名与 Java 对象的属性名不一致,可以在 SQL 中使用别名。例如:
@Select("SELECT id, name AS userName, age FROM users WHERE id = #{id}")
User getUserById(int id);
这样 MyBatis 就能将查询结果中的 userName
列映射到 Java 对象中的 userName
属性上。
2. 结果映射(Result Map)
对于更复杂的情况,可以在 XML 中通过 <resultMap>
标签来定义映射关系。这样不仅灵活,而且可在一个地方统一管理映射规则。例如:
<resultMap id="userResultMap" type="com.example.User">
<id column="id" property="id"/>
<result column="name" property="userName"/>
<result column="age" property="age"/>
</resultMap>
<select id="getUserById" resultMap="userResultMap" parameterType="int">
SELECT id, name, age FROM users WHERE id = #{id}
</select>
此方式适用于字段较多、数据结构较复杂或者需要复用映射规则的场景。
3. 开启驼峰命名(Camel Case Mapping)
MyBatis 还支持通过全局配置来自动将下划线命名转换为驼峰命名,这样数据库列 user_name
会自动映射到 Java 属性 userName
。可以在配置文件中启用该功能:
<settings>
<setting name="mapUnderscoreToCamelCase" value="true"/>
<!-- 也可以设置日志输出,见下节 -->
<setting name="logImpl" value="STDOUT_LOGGING"/>
</settings>
或者在 application.yml
中(使用 MyBatis-Spring Boot Starter 时)这样配置:
mybatis:
configuration:
map-underscore-to-camel-case: true
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
这种方式使得数据库列名与 Java 属性之间的差异无需在每个 SQL 中显式别名,从而减少了维护成本。
三、配置日志打印 SQL、参数及执行结果
为了帮助调试,MyBatis 允许开发者配置日志输出,打印 SQL 语句、参数绑定以及执行结果。主要方法有:
1. 配置 MyBatis 日志实现
MyBatis 支持多种日志实现(例如:STDOUT_LOGGING、LOG4J、SLF4J 等)。可以在 MyBatis 配置文件中设置日志实现:
<settings>
<setting name="logImpl" value="STDOUT_LOGGING"/>
</settings>
此配置会将所有 SQL 执行、参数绑定以及执行结果输出到控制台。
2. 配置日志框架
如果项目中使用 Log4j2 或 SLF4J 等日志框架,则需要在日志配置文件中启用 MyBatis 相关的日志记录器。例如,在 Log4j2 的配置文件中:
<Logger name="org.apache.ibatis" level="DEBUG" additivity="false">
<AppenderRef ref="Console"/>
</Logger>
这样便能确保 MyBatis 执行过程中的详细日志输出到控制台,便于调试和性能分析。
3. 配置 application.yml 打印日志
logging:
level:
com.yourpackage.mapper: debug
mybatis:
configuration:
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
4. 运行时调试效果
调试过程中,会看到类似下面的日志输出:
DEBUG - ==> Preparing: SELECT id, name, age FROM users WHERE id = ?
DEBUG - ==> Parameters: 1(Integer)
DEBUG - <== Total: 1
这显示了待执行的 SQL 语句、参数绑定情况以及执行结果的行数,极大地帮助开发者定位问题。
示例代码总结
注解方式示例(带驼峰配置)
@Mapper
public interface UserMapper {
@Select("SELECT id, name AS userName, age FROM users WHERE id = #{id}")
User getUserById(int id);
@Select("SELECT id, name AS userName, age FROM users")
List<User> getAllUsers();
}
XML 配置示例(使用 resultMap)
<resultMap id="userResultMap" type="com.example.User">
<id column="id" property="id"/>
<result column="name" property="userName"/>
<result column="age" property="age"/>
</resultMap>
<select id="getUserById" resultMap="userResultMap" parameterType="int">
SELECT id, name, age FROM users WHERE id = #{id}
</select>
<select id="getAllUsers" resultMap="userResultMap">
SELECT id, name, age FROM users
</select>
全局配置开启驼峰命名与日志输出(例如,在 mybatis-config.xml 中)
<settings>
<setting name="mapUnderscoreToCamelCase" value="true"/>
<setting name="logImpl" value="STDOUT_LOGGING"/>
</settings>
案例说明(JDBC和Mybaits操作数据库案例对比)
假设有一个简单的 User
表,结构如下(MySQL 语法示例):
CREATE TABLE users (
id INT AUTO_INCREMENT PRIMARY KEY,
username VARCHAR(50) NOT NULL,
password VARCHAR(255) NOT NULL,
email VARCHAR(100),
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
对应的 Java 实体类 User
如下:
public class User {
private Integer id;
private String username;
private String password;
private String email;
private Timestamp createdAt;
// Getters and Setters
}
Part 1:基于 JDBC 实现 CRUD
1.1 JDBC 工具类
创建一个简单的 JDBC 工具类,用于获取数据库连接并释放资源。
import java.sql.*;
public class JDBCUtil {
private static final String URL = "jdbc:mysql://localhost:3306/testdb?useSSL=false&serverTimezone=UTC";
private static final String USERNAME = "root";
private static final String PASSWORD = "root123";
static {
try {
Class.forName("com.mysql.cj.jdbc.Driver");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
public static Connection getConnection() throws SQLException {
return DriverManager.getConnection(URL, USERNAME, PASSWORD);
}
public static void close(Connection conn, Statement stmt, ResultSet rs) {
try { if(rs != null) rs.close(); } catch (Exception e) { e.printStackTrace(); }
try { if(stmt != null) stmt.close(); } catch (Exception e) { e.printStackTrace(); }
try { if(conn != null) conn.close(); } catch (Exception e) { e.printStackTrace(); }
}
}
1.2 JDBC 实现 CRUD 的 DAO
import java.sql.*;
import java.util.ArrayList;
import java.util.List;
public class UserJDBCDao {
// 增
public int insertUser(User user) {
String sql = "INSERT INTO users(username, password, email) VALUES (?, ?, ?)";
Connection conn = null;
PreparedStatement pstmt = null;
try {
conn = JDBCUtil.getConnection();
pstmt = conn.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS);
pstmt.setString(1, user.getUsername());
pstmt.setString(2, user.getPassword());
pstmt.setString(3, user.getEmail());
int rows = pstmt.executeUpdate();
// 获取自增主键
ResultSet rs = pstmt.getGeneratedKeys();
if (rs.next()) {
user.setId(rs.getInt(1));
}
rs.close();
return rows;
} catch (SQLException e) {
e.printStackTrace();
return 0;
} finally {
JDBCUtil.close(conn, pstmt, null);
}
}
// 删
public int deleteUserById(int id) {
String sql = "DELETE FROM users WHERE id = ?";
Connection conn = null;
PreparedStatement pstmt = null;
try {
conn = JDBCUtil.getConnection();
pstmt = conn.prepareStatement(sql);
pstmt.setInt(1, id);
return pstmt.executeUpdate();
} catch (SQLException e) {
e.printStackTrace();
return 0;
} finally {
JDBCUtil.close(conn, pstmt, null);
}
}
// 改
public int updateUserEmail(int id, String newEmail) {
String sql = "UPDATE users SET email = ? WHERE id = ?";
Connection conn = null;
PreparedStatement pstmt = null;
try {
conn = JDBCUtil.getConnection();
pstmt = conn.prepareStatement(sql);
pstmt.setString(1, newEmail);
pstmt.setInt(2, id);
return pstmt.executeUpdate();
} catch (SQLException e) {
e.printStackTrace();
return 0;
} finally {
JDBCUtil.close(conn, pstmt, null);
}
}
// 查 ------ 查询单个
public User getUserById(int id) {
String sql = "SELECT * FROM users WHERE id = ?";
Connection conn = null;
PreparedStatement pstmt = null;
ResultSet rs = null;
try {
conn = JDBCUtil.getConnection();
pstmt = conn.prepareStatement(sql);
pstmt.setInt(1, id);
rs = pstmt.executeQuery();
if (rs.next()) {
User user = new User();
user.setId(rs.getInt("id"));
user.setUsername(rs.getString("username"));
user.setPassword(rs.getString("password"));
user.setEmail(rs.getString("email"));
user.setCreatedAt(rs.getTimestamp("created_at"));
return user;
}
} catch (SQLException e) {
e.printStackTrace();
} finally {
JDBCUtil.close(conn, pstmt, rs);
}
return null;
}
// 查 ------ 查询列表
public List<User> getAllUsers() {
String sql = "SELECT * FROM users";
Connection conn = null;
PreparedStatement pstmt = null;
ResultSet rs = null;
List<User> list = new ArrayList<>();
try {
conn = JDBCUtil.getConnection();
pstmt = conn.prepareStatement(sql);
rs = pstmt.executeQuery();
while (rs.next()) {
User user = new User();
user.setId(rs.getInt("id"));
user.setUsername(rs.getString("username"));
user.setPassword(rs.getString("password"));
user.setEmail(rs.getString("email"));
user.setCreatedAt(rs.getTimestamp("created_at"));
list.add(user);
}
} catch (SQLException e) {
e.printStackTrace();
} finally {
JDBCUtil.close(conn, pstmt, rs);
}
return list;
}
}
1.3 JDBC 测试代码示例
public class TestJDBC {
public static void main(String[] args) {
UserJDBCDao dao = new UserJDBCDao();
// 插入数据
User newUser = new User();
newUser.setUsername("Bob");
newUser.setPassword("pass123");
newUser.setEmail("[email protected]");
int insertRows = dao.insertUser(newUser);
System.out.println("JDBC 插入行数:" + insertRows + ", 生成的ID:" + newUser.getId());
// 更新数据
int updateRows = dao.updateUserEmail(newUser.getId(), "[email protected]");
System.out.println("JDBC 更新行数:" + updateRows);
// 查询数据
User queryUser = dao.getUserById(newUser.getId());
System.out.println("JDBC 查询到的用户:" + queryUser.getUsername() + ", Email:" + queryUser.getEmail());
// 删除数据
int deleteRows = dao.deleteUserById(newUser.getId());
System.out.println("JDBC 删除行数:" + deleteRows);
}
}
JDBC 实现的优缺点
-
优点:
- 灵活度高,对连接、事务、异常处理有完全控制
-
缺点:
-
大量重复代码(获取连接、释放资源、异常处理)
-
代码冗长,可读性和维护性较差
-
Part 2:基于 MyBatis 重构 CRUD
2.1 MyBatis 配置
配置文件(例如 application.yml
部分):
spring:
datasource:
url: jdbc:mysql://localhost:3306/testdb?useSSL=false&serverTimezone=UTC
username: root
password: root123
driver-class-name: com.mysql.cj.jdbc.Driver
mybatis:
mapper-locations: classpath:mapper/*.xml
type-aliases-package: com.example.demo.model
configuration:
map-underscore-to-camel-case: true
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
2.2 MyBatis Mapper 接口与映射文件
Mapper 接口(UserMapper.java)
package com.example.demo.mapper;
import com.example.demo.model.User;
import org.apache.ibatis.annotations.*;
import java.util.List;
public interface UserMapper {
@Insert("INSERT INTO users(username, password, email) VALUES (#{username}, #{password}, #{email})")
@Options(useGeneratedKeys = true, keyProperty = "id", keyColumn = "id")
int insertUser(User user);
@Delete("DELETE FROM users WHERE id = #{id}")
int deleteUserById(@Param("id") int id);
@Update("UPDATE users SET email = #{email} WHERE id = #{id}")
int updateUserEmail(@Param("id") int id, @Param("email") String email);
@Select("SELECT * FROM users WHERE id = #{id}")
User getUserById(@Param("id") int id);
@Select("SELECT * FROM users")
List<User> getAllUsers();
}
对应 XML 映射文件(可选,下面以注解方式为主,略)
如果需要使用 XML 映射,可以将 SQL 语句放在
resources/mapper/UserMapper.xml
中,并在接口中不采用注解。
2.3 MyBatis 测试代码示例
使用 Spring Boot 进行单元测试:
import com.example.demo.mapper.UserMapper;
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;
@SpringBootTest
public class UserMapperTest {
@Autowired
private UserMapper userMapper;
@Test
public void testInsertUser() {
User user = new User();
user.setUsername("Alice");
user.setPassword("alicepass");
user.setEmail("[email protected]");
int rows = userMapper.insertUser(user);
System.out.println("MyBatis 插入行数:" + rows);
System.out.println("生成的主键 ID:" + user.getId());
}
@Test
public void testUpdateUserEmail() {
int rows = userMapper.updateUserEmail(1, "[email protected]");
System.out.println("MyBatis 更新行数:" + rows);
}
@Test
public void testGetUserById() {
User user = userMapper.getUserById(1);
System.out.println("MyBatis 查询到的用户:" + user.getUsername() + ", Email:" + user.getEmail());
}
@Test
public void testDeleteUser() {
int rows = userMapper.deleteUserById(1);
System.out.println("MyBatis 删除行数:" + rows);
}
@Test
public void testGetAllUsers() {
List<User> users = userMapper.getAllUsers();
users.forEach(user -> System.out.println("用户:" + user.getUsername() + ", Email:" + user.getEmail()));
}
}
MyBatis 实现的优缺点
-
优点:
-
极大减少重复代码,无需手动管理连接和资源
-
通过注解或 XML 映射,SQL 与 Java 代码分离,维护性更高
-
内置功能强大,例如动态 SQL、自动映射、日志输出等
-
-
缺点:
-
初期配置及学习曲线略高
-
对于非常简单的场景,可能显得"杀鸡用牛刀"
-
Part 3:实际测试结果对比(IDEA 运行日志截图模拟)
JDBC 版运行日志(示例输出):
JDBC 插入行数:1, 生成的ID:10
JDBC 更新行数:1
JDBC 查询到的用户:Bob, Email:[email protected]
JDBC 删除行数:1
说明:运行过程中,各步骤都需要手动捕获异常及关闭连接,在 IDEA 控制台可见大量重复日志信息。
MyBatis 版运行日志(示例输出):
==> Preparing: INSERT INTO users(username, password, email) VALUES (?,?,?)
==> Parameters: Alice(String), alicepass(String), [email protected](String)
<== Updates: 1
MyBatis 插入行数:1
生成的主键 ID:12
==> Preparing: UPDATE users SET email = ? WHERE id = ?
==> Parameters: [email protected](String), 1(Integer)
<== Updates: 1
MyBatis 更新行数:1
==> Preparing: SELECT * FROM users WHERE id = ?
==> Parameters: 1(Integer)
<== Total: 1
MyBatis 查询到的用户:Alice, Email:[email protected]
==> Preparing: DELETE FROM users WHERE id = ?
==> Parameters: 1(Integer)
<== Updates: 1
MyBatis 删除行数:1
说明:通过 MyBatis 的日志配置,可直接在控制台看到 SQL 语句、绑定参数及执行结果,大幅提升调试效率与可读性。
总结对比
-
代码量:
JDBC 实现需要大量重复代码(连接、语句、资源关闭等),而 MyBatis 通过映射注解和配置文件大大减少了冗余。
-
易用性:
使用 MyBatis 后,开发者可以专注于 SQL 和业务逻辑,无需关注细节的资源管理;同时日志配置方便调试。
-
维护性:
JDBC 代码中 SQL 嵌入 Java 中导致耦合度高,修改一处需要重新编译;而 MyBatis 通过 XML 或注解实现 SQL 与 Java 的分离,使得后期维护更加高效。
-
调试:
MyBatis 内置日志输出(显示具体 SQL、参数、执行结果),使问题排查变得简单直观,而 JDBC 的日志需要自行实现和维护。
结论
通过上面的案例演示,可以看到 MyBatis 在开发体验、代码维护与调试方面均优于传统的 JDBC 实现。在现代项目中,推荐优先考虑基于 MyBatis 或类似框架来进行数据持久化操作,从而提高整体开发效率与代码可维护性。
实际截图说明:
在 IDEA 中运行测试时,你可以截取各个测试方法的控制台日志。
例如:
JDBC 版的日志截图显示"JDBC 插入行数:1, 生成的ID:10"等信息。
MyBatis 版截图则包含了标准输出的 SQL 语句、参数及执行统计信息(类似上面的日志示例)。
由于本回答无法直接上传图片,你可以自行在 IDEA 中运行上述测试代码并截图保存以作参考。
希望这个完整的小案例能帮助你深刻理解传统 JDBC 与 MyBatis 在 CRUD 操作上的差异,并体会到 MyBatis 在简化代码和提高开发效率方面的优势!
结语 🎉
本文详细讲解了 MyBatis 基础 CRUD 操作的各个方面,从增删改查的基本语法到注解和 XML 映射方式的具体实现,再到参数绑定、自动映射和日志调试的使用技巧。通过这些示例与对比,我们可以发现:
-
简化开发流程:MyBatis 通过灵活的 SQL 映射机制,大幅减少了传统 JDBC 开发中冗长且重复的代码。
-
增强代码可维护性:SQL 语句与 Java 代码的分离使得代码结构更清晰,修改和扩展更加方便,解决了 SQL 与业务逻辑耦合的问题。
-
方便调试与追踪:借助日志配置,开发者能够直观地查看 SQL 语句、参数绑定和执行结果,显著提高了调试效率。
-
灵活应对复杂场景:无论是简单 CRUD 操作还是复杂的动态 SQL 构造,MyBatis 都能提供有效的支持,满足不同项目的需求。
总体来看,MyBatis 为开发者提供了一个高效、灵活和易维护的数据持久层解决方案,使得构建健壮和可扩展的企业级应用成为可能。希望本篇文章能帮助你更好地理解和掌握 MyBatis 的核心技术,并在实际项目中充分发挥其优势!🚀
继续深入探索 MyBatis 及其它持久化技术,你的开发技能必将更上一层楼!😊