MyBatis 對映

最後更新: 2025-10-21 15:55:03 +0800 +0800
tags: Java | Mybatis | Sql
原文以英文撰寫。您正在閱讀AI翻譯版本。

MyBatis 將 Java 呼叫對映至 SQL 陳述式,而參數繫結、陳述式執行與結果集存取則由 JDBC 負責。對映器應讓這個邊界清楚可見:SQL 欄位名稱屬於陳述式,Java 屬性名稱屬於 參數對映與結果對映,任何非標準轉換都應由型別處理器在兩者之間執行。

參數與結果邊界 #

簡單參數可以使用 #{id} 佔位符。物件與 Map 參數會公開具名屬性;對於多個對映器 參數,應使用 @Param,使名稱不依賴編譯器中繼資料:

java
List<Task> findByState(@Param("state") State state,
                       @Param("limit") int limit);

#{...} 會建立 JDBC 參數標記並繫結值。${...} 會在準備 SQL 之前將文字代入 SQL, 因此僅限於允許清單中的識別碼或無法參數化的片段。絕不能將請求資料直接放入 ${...} 運算式。

當欄位標籤與 Java 屬性相符時,自動結果對映較為簡潔。名稱不同、巢狀物件需要明確 識別,或聯結可能造成父資料列重複時,應使用 resultMap:

xml
<resultMap id="taskResult" type="com.example.Task">
  <id property="id" column="task_id"/>
  <result property="name" column="task_name"/>
  <result property="state" column="state"
          typeHandler="com.example.StateTypeHandler"/>
</resultMap>

<id> 對映會識別聯結結果中的物件,並協助 MyBatis 合併重複的父資料。它不會宣告 資料庫條件約束;結構描述仍必須強制執行識別性。

產生的索引鍵 #

對於支援產生索引鍵的資料庫與 JDBC 驅動程式,啟用 useGeneratedKeys 並指定可寫入的 Java 屬性。MyBatis 會在插入後呼叫 JDBC 產生索引鍵 API,並將產生的主索引鍵指派給 該屬性。

xml
<insert id="insert"
        parameterType="com.example.Task"
        useGeneratedKeys="true"
        keyProperty="id">
  INSERT INTO task (name) VALUES (#{name})
</insert>
java
Task task = new Task();
task.setName("import");
mapper.insert(task);
long id = task.getId();

指派只會填入產生索引鍵的屬性,不會重新載入資料庫預設值、觸發器產生的欄位或其他 不相關欄位。請使用後續的 SELECT、資料庫支援時的 RETURNING 子句,或在資料庫 使用序列或驅動程式不支援 getGeneratedKeys 時使用 selectKey 陳述式。

Null 參數 #

xml
UPDATE task
SET completed_at = #{completedAt, jdbcType=TIMESTAMP}
WHERE id = #{id}

只有在資料庫慣例與所有可為 null 的參數相容時,才設定全域 jdbcTypeForNull。對於 具有不同 SQL 型別的欄位,針對每個參數指定型別更加清楚。由於產生索引鍵與 null 繫結行為取決於驅動程式,請使用正式環境的驅動程式測試插入與更新。

動態 SQL 與型別處理器 #

動態元素可以建構陳述式結構,而不必串接任意應用程式文字:

xml
<select id="find" resultMap="taskResult">
  SELECT id AS task_id, name AS task_name, state
  FROM task
  <where>
    <if test="state != null">
      state = #{state, typeHandler=com.example.StateTypeHandler}
    </if>
  </where>
  ORDER BY id
</select>

只有在子元素輸出條件時,<where> 才會插入 WHERE,並移除開頭的 AND 或 OR。 相關元素包括 <choose>、<set>、<trim> 與 <foreach>。TypeHandler 應定義 刻意設計的 Java/JDBC 表示方式,例如將列舉儲存為穩定字串;若不同欄位以不同方式 編碼相同的 Java 型別,應進行窄範圍註冊。

工作階段與交易所有權 #

對映的陳述式會透過 SqlSession 執行。直接使用 MyBatis 時,呼叫方會開啟工作階段、 提交或回復交易,並關閉工作階段:

java
try (SqlSession session = factory.openSession()) {
    TaskMapper mapper = session.getMapper(TaskMapper.class);
    mapper.insert(task);
    session.commit();
}

預設工作階段不是自動提交模式,且 SqlSession 不具備執行緒安全性。MyBatis-Spring 等架構整合會將工作階段繫結至架構管理的交易;應用程式程式碼不得將手動提交與該 所有權模型混用。產生索引鍵的指派發生在陳述式執行期間,但只有在擁有該交易的交易 提交後,資料列才會持久化。

參考資料 #

評論

在 GitHub 上閱讀或評論(發表評論需要登入)