MyBatis 作為半自動 ORM 框架,將 SQL 寫在 XML 或註解中,保留了對 SQL 的完全控制權,適合複雜查詢、性能敏感場景。本文聚焦:通用 CRUD 封裝、分頁插件集成、動態 SQL 技巧、性能優化要點。
<resultMap id="userMap" type="com.example.User">
<id property="id" column="user_id"/>
<result property="username" column="user_name"/>
<result property="email" column="email"/>
<result property="createdAt" column="created_at"/>
</resultMap>
<!-- 插入 -->
<insert id="insert" parameterType="User" useGeneratedKeys="true" keyProperty="id">
INSERT INTO sys_user(user_name, email, created_at)
VALUES(#{username}, #{email}, NOW())
</insert>
<!-- 刪除 -->
<delete id="deleteById">
DELETE FROM sys_user WHERE user_id = #{id}
</delete>
<!-- 更新 -->
<update id="update">
UPDATE sys_user
SET user_name = #{username}, email = #{email}
WHERE user_id = #{id}
</update>
<!-- 單查 -->
<select id="selectById" resultMap="userMap">
SELECT user_id, user_name, email, created_at FROM sys_user WHERE user_id = #{id}
</select>
<!-- 列表查詢 -->
<select id="selectList" resultMap="userMap">
SELECT user_id, user_name, email, created_at FROM sys_user
<where>
<if test="username != null">AND user_name LIKE CONCAT('%', #{username}, '%')</if>
<if test="email != null">AND email = #{email}</if>
</where>
ORDER BY created_at DESC
</select>
引入依賴:
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper-spring-boot-starter</artifactId>
<version>1.4.6</version>
</dependency>
配置 application.yml:
pagehelper:
helper-dialect: mysql
reasonable: true
support-methods-arguments: true
params: count=countSql
使用極簡:
PageHelper.startPage(pageNum, pageSize);
List<User> list = userMapper.selectList(param);
PageInfo<User> pageInfo = new PageInfo<>(list);
// pageInfo.getTotal(), pageInfo.getPages(), pageInfo.getList()
原理:攔截 Executor.query,根據數據庫方言自動改寫 SQL 追加 LIMIT/OFFSET(MySQL)、ROWNUM(Oracle)、OFFSET FETCH(PostgreSQL/SQL Server 2012+)。
一次性查全量再內存分頁,僅適用於極小數據集(< 1000 行)。
<select id="selectPage" resultMap="userMap">
SELECT * FROM sys_user
<where>...</where>
ORDER BY created_at DESC
LIMIT #{offset}, #{pageSize}
</select>
<select id="selectCount" resultType="long">
SELECT COUNT(1) FROM sys_user <where>...</where>
</select>
Service 層手動組裝 PageResult。缺點:代碼侵入性強、維護成本高、易出錯。
<where> 智能去除首個 AND/OR<trim prefix="WHERE" prefixOverrides="AND |OR"> 更靈活的條件拼接<foreach collection="ids" item="id" separator=",">#{id}</foreach> 實現 IN 列表<bind name="pattern" value="'%' + username + '%'" /> 變量預綁定簡化 LIKE<choose><when><otherwise> 互斥條件分支<association>/<collection> 替代多次查詢(N+1 問題)。INSERT INTO t(a,b) VALUES <foreach>(#{item.a},#{item.b})</foreach>,單條提交效率極低。<cache/>,配合 Ehcache/Redis。EXPLAIN 核心慢查詢,補充索引。| 問題 | 原因 | 解決 |
|---|---|---|
| 分頁總數錯誤 | Count SQL 自動生成失敗(複雜關聯/子查詢) | 手寫 Count SQL 或配置 countSql |
| 映射報錯 | 列名與屬性名不一致、未配置 resultMap | 統一使用 resultMap、開啟 mapUnderscoreToCamelCase |
| 批量插入超限 | MySQL max_allowed_packet / 佔位符超過 65535 | 分批提交、調大參數、改用 LOAD DATA |
| 緩存髒讀 | 二級緩存未正確失效 | 增刪改配置 flushCache="true"、合理設置 eviction |
MyBatis 給予 SQL 完全控制權,配合 PageHelper 實現零侵入分頁,動態 XML 構建靈活查詢。遵循「顯式列映射、物理分頁、批量操作、緩存策略」四原則,可構建高性能、易維護的持久層。