Mapper 介面:
List queryList(String workerId, Integer topNum);
XML:
<select id="queryList" resultType="com.demo.RecordVo">
SELECT ID id, WORKER_ID workerId, UPDATE_DATE updateDate
FROM USER_RECORDS t
WHERE t.WORKER_ID = #{0}
LIMIT #{1}
</select>
#{0} 對應第一個參數,#{1} 對應第二個。簡單但可讀性較差。
Mapper 介面:
Integer queryCountByWorkerId(Map queryParam);
XML:
<select id="queryCountByWorkerId" parameterType="java.util.Map" resultType="java.lang.Integer">
SELECT COUNT(1)
FROM tableName F
WHERE F.WORKER_ID = #{workerId}
</select>
Map key / POJO 屬性名直接對應 #{propertyName}。清晰、可維護、支援複雜查詢條件。
Mapper 介面:
Integer queryCountByWorkerId(@Param("workerId") String workerId);
XML 同 1.2。本質上 MyBatis 將其封裝為 Map。
<resultMap type="com.demo.DataModule" id="dataModule">
<result column="ID" property="id" />
<result column="CREATE_DATE" property="createDate" />
<result column="WORKERID" property="workerId" />
<result column="UPDATE_DATE" property="updateDate" />
<result column="STATUS" property="status" />
</resultMap>
<select id="queryAll" resultMap="dataModule">
SELECT ID, CREATE_DATE, WORKERID, UPDATE_DATE, STATUS FROM tableName
</select>
SQL 查詢欄位用資料庫原名,resultMap 負責映射轉換。
<select id="queryAll" resultType="com.demo.DataModule">
SELECT ID id, CREATE_DATE createDate, WORKERID workerId FROM tableName
</select>
SQL 別名必須精確匹配實體類屬性名(駝峰命名)。簡潔但要求嚴格命名規範。
適用於:動態建表、複雜報表、跨庫查詢、SQL 由前端/配置產生。
public class ParamVo {
private String sql;
// getter/setter
}
int executeCreateSql(ParamVo vo); // DDL/DML
List
<update id="executeCreateSql">
${sql}
</update>
<select id="executeSelectSql" resultType="java.util.Map">
${sql}
</select>
警告:${} 為直接字串替換,**極高風險 SQL 注入**。
僅限可信內部系統、嚴格驗證 SQL 白名單、或唯讀查詢場景。生產環境極謹慎使用!
<sql id="queryChild">
FROM tableName1 F
RIGHT JOIN tableName2 C ON F.WORKER_ID = C.WORKER_ID
WHERE F.STATUS = 1 AND F.WORKER_ID = #{workerId}
ORDER BY C.CREATE_DATE DESC
</sql>
<select id="queryCountByWorkerId" parameterType="java.util.Map" resultType="java.lang.Integer">
SELECT COUNT(1)
<include refid="queryChild"/>
</select>
<select id="queryListByWorkerId" parameterType="java.util.Map" resultType="com.demo.RecordVo">
SELECT ID id, WORKER_ID workerId, UPDATE_DATE updateDate, ...
<include refid="queryChild"/>
</select>
適用場景:共同 WHERE 條件、JOIN 關聯、排序分頁、公共欄位選擇。
| 技巧 | 說明 | 注意事項 |
|---|---|---|
| #{ } vs ${ } | #{} 預編譯參數化(安全),${} 字串替換(靈活但危險) | 99% 場景用 #{},${} 僅用於表名、欄位名、排序欄位等無法參數化處 |
| resultType vs resultMap | resultType 簡單自動映射,resultMap 複雜映射、關聯、嵌套 | 一對多、多對一、嵌套結果必須用 resultMap |
| 動態 SQL | <if>, <choose>, <where>, <trim>, <foreach> | <where> 自動處理 AND/OR 前綴,<trim> 更靈活 |
| 分頁插件 | PageHelper、MyBatis-Plus 内建分頁 | 物理分頁優於邏輯分頁,避免全量查詢 |
| 類型處理器 | 自定義 TypeHandler 處理 Enum、JSON、加密欄位 | 註冊於配置或 @MappedTypes |
最佳實踐:
1. 統一使用 Map/POJO + resultMap 模式
2. 複雜查詢優先考慮 SQL 片段複用
3. 動態 SQL 善用 <where><trim> 避免語法錯誤
4. 原生 SQL 列為最後手段,務必做注入防護
5. 關鍵查詢加上註釋/* +MAX_EXECUTION_TIME(1000) */防慢查詢