前言 🌟
在掌握了 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 usersSET 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 usersSET name = #{name}, age = #{age}WHERE id = #{id}</update>
-
多個參數(使用 @Param):
<update id="updateUser" parameterType="map">UPDATE usersSET 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: truelog-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("bob@example.com");int insertRows = dao.insertUser(newUser);System.out.println("JDBC 插入行數:" + insertRows + ", 生成的ID:" + newUser.getId());// 更新數據int updateRows = dao.updateUserEmail(newUser.getId(), "bob_new@example.com");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=UTCusername: rootpassword: root123driver-class-name: com.mysql.cj.jdbc.Drivermybatis:mapper-locations: classpath:mapper/*.xmltype-aliases-package: com.example.demo.modelconfiguration:map-underscore-to-camel-case: truelog-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 {@Autowiredprivate UserMapper userMapper;@Testpublic void testInsertUser() {User user = new User();user.setUsername("Alice");user.setPassword("alicepass");user.setEmail("alice@example.com");int rows = userMapper.insertUser(user);System.out.println("MyBatis 插入行數:" + rows);System.out.println("生成的主鍵 ID:" + user.getId());}@Testpublic void testUpdateUserEmail() {int rows = userMapper.updateUserEmail(1, "alice_new@example.com");System.out.println("MyBatis 更新行數:" + rows);}@Testpublic void testGetUserById() {User user = userMapper.getUserById(1);System.out.println("MyBatis 查詢到的用戶:" + user.getUsername() + ", Email:" + user.getEmail());}@Testpublic void testDeleteUser() {int rows = userMapper.deleteUserById(1);System.out.println("MyBatis 刪除行數:" + rows);}@Testpublic 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:bob_new@example.com
JDBC 刪除行數:1
說明:運行過程中,各步驟都需要手動捕獲異常及關閉連接,在 IDEA 控制臺可見大量重復日志信息。
MyBatis 版運行日志(示例輸出):
==> Preparing: INSERT INTO users(username, password, email) VALUES (?,?,?)
==> Parameters: Alice(String), alicepass(String), alice@example.com(String)
<== Updates: 1
MyBatis 插入行數:1
生成的主鍵 ID:12==> Preparing: UPDATE users SET email = ? WHERE id = ?
==> Parameters: alice_new@example.com(String), 1(Integer)
<== Updates: 1
MyBatis 更新行數:1==> Preparing: SELECT * FROM users WHERE id = ?
==> Parameters: 1(Integer)
<== Total: 1
MyBatis 查詢到的用戶:Alice, Email:alice_new@example.com==> 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 及其它持久化技術,你的開發技能必將更上一層樓!😊