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 上阅读或评论(发表评论需要登录)