MyBatis 将 Java 调用映射到 SQL 语句,而参数绑定、语句执行和结果集访问由 JDBC 负责。映射器应使这一边界清晰可见:SQL 列名属于语句,Java 属性名属于参数映射和 结果映射,任何非标准转换都应由类型处理器在二者之间执行。
参数与结果边界 #
简单参数可以使用 #{id} 占位符。对象参数和 Map 参数会公开命名属性;对于多个映射器
参数,应使用 @Param,使参数名不依赖编译器元数据:
List<Task> findByState(@Param("state") State state,
@Param("limit") int limit);#{...} 会创建 JDBC 参数标记并绑定值。${...} 会在准备 SQL 之前将文本替换到 SQL
中,因此只能用于允许列表中的标识符或无法参数化的片段。绝不能将请求数据直接放入
${...} 表达式。
当列标签与 Java 属性匹配时,自动结果映射较为简洁。当名称不同时、嵌套对象需要显式
标识时,或连接可能产生重复的父行时,应使用 resultMap:
<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,并将生成的主键赋给该属性。
<insert id="insert"
parameterType="com.example.Task"
useGeneratedKeys="true"
keyProperty="id">
INSERT INTO task (name) VALUES (#{name})
</insert>Task task = new Task();
task.setName("import");
mapper.insert(task);
long id = task.getId();此赋值只会填充生成键属性,不会重新加载数据库默认值、触发器生成的列或其他无关字段。
应使用后续的 SELECT、数据库支持时的 RETURNING 子句,或者在数据库使用序列或驱动
程序不支持 getGeneratedKeys 时使用 selectKey 语句。
NULL 参数 #
UPDATE task
SET completed_at = #{completedAt, jdbcType=TIMESTAMP}
WHERE id = #{id}只有在数据库约定与所有可为 NULL 的参数兼容时,才应设置全局
jdbcTypeForNull。对于 SQL 类型不同的列,按参数指定类型更加清晰。由于生成键和
NULL 绑定行为取决于驱动程序,应使用生产环境中的驱动程序测试插入和更新操作。
动态 SQL 与类型处理器 #
动态元素可以构建语句结构,而无需拼接任意应用程序文本:
<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 时,调用方负责打开会话、提交或
回滚事务,以及关闭会话:
try (SqlSession session = factory.openSession()) {
TaskMapper mapper = session.getMapper(TaskMapper.class);
mapper.insert(task);
session.commit();
}默认会话不是自动提交模式,且 SqlSession 不是线程安全的。MyBatis-Spring 等框架
集成会将会话绑定到由框架管理的事务中;应用程序代码不得将手动提交与该所有权模型
混用。生成键赋值发生在语句执行期间,但只有在所属事务提交后,该行才会持久化。
评论
在 GitHub 上阅读或评论(发表评论需要登录)