MyBatis SQL 映射文件的作用和结构
MyBatis SQL 映射文件定义了 SQL 语句以及如何将 SQL 语句的参数和结果映射到 Java 对象。
一、 作用 (Purpose)
MyBatis SQL 映射文件(通常命名为 XXXMapper.xml
)的主要作用是:
- 定义 SQL 语句: 在 XML 映射文件中编写 SQL 语句,包括 SELECT, INSERT, UPDATE, DELETE 等各种类型的 SQL 语句。
- 参数映射 (Parameter Mapping): 定义如何将 Java 方法的参数映射到 SQL 语句中的参数。 可以使用
#
和$
占位符,并指定参数类型、jdbcType 等信息。 - 结果映射 (Result Mapping): 定义如何将 SQL 语句的查询结果映射到 Java 对象。 可以使用
resultType
或resultMap
,并定义一对一、一对多等关系映射。 - 动态 SQL (Dynamic SQL): 使用 MyBatis 提供的动态 SQL 元素 (例如
<if>
,<choose>
,<when>
,<otherwise>
,<where>
,<set>
,<foreach>
),根据不同的条件动态生成 SQL 语句。 - 缓存配置 (Cache Configuration): 配置 SQL 语句的缓存行为,提高查询性能。
- 与 Mapper 接口关联: 将 SQL 映射文件与 Java Mapper 接口关联起来,使得可以通过调用 Mapper 接口的方法来执行 SQL 语句。
总而言之,SQL 映射文件是 MyBatis 将 SQL 语句与 Java 代码解耦的关键,它允许开发者专注于 SQL 语句的编写和优化,而无需关心 JDBC 的细节。
二、 结构 (Structure)
MyBatis SQL 映射文件的根元素是 <mapper>
,它包含多个子元素,用于定义 SQL 语句、参数映射、结果映射等信息。 以下是一个典型的 SQL 映射文件结构:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.example.mapper.UserMapper">
<!-- 1. cache (缓存) -->
<cache
eviction="LRU"
flushInterval="60000"
readOnly="true"
size="512"/>
<!-- 2. resultMap (结果映射) -->
<resultMap id="UserResultMap" type="com.example.model.User">
<id property="id" column="id"/>
<result property="username" column="username"/>
<result property="email" column="email"/>
<!-- association (一对一) -->
<association property="address" column="address_id" javaType="com.example.model.Address"
select="com.example.mapper.AddressMapper.selectAddressById"/>
<!-- collection (一对多) -->
<collection property="orders" column="id" ofType="com.example.model.Order"
select="com.example.mapper.OrderMapper.selectOrdersByUserId"/>
</resultMap>
<!-- 3. select (查询) -->
<select id="selectUserById" parameterType="int" resultMap="UserResultMap" useCache="true">
SELECT * FROM user WHERE id = #{id}
</select>
<!-- 4. insert (插入) -->
<insert id="insertUser" parameterType="com.example.model.User" useGeneratedKeys="true" keyProperty="id">
INSERT INTO user (username, email) VALUES (#{username}, #{email})
</insert>
<!-- 5. update (更新) -->
<update id="updateUser" parameterType="com.example.model.User">
UPDATE user SET username = #{username}, email = #{email} WHERE id = #{id}
</update>
<!-- 6. delete (删除) -->
<delete id="deleteUserById" parameterType="int">
DELETE FROM user WHERE id = #{id}
</delete>
<!-- 7. sql (SQL 片段) -->
<sql id="userColumns">
id, username, email
</sql>
</mapper>
三、各个元素详解
-
<mapper>
(根元素):namespace
属性:指定 Mapper 接口的完全限定名。 MyBatis 会根据这个命名空间来查找 SQL 映射文件,并将 SQL 语句与 Mapper 接口的方法关联起来。 这是将 SQL 映射文件与 Java 代码关联的关键。
例如:<mapper namespace="com.example.mapper.UserMapper">
对应着UserMapper.java
接口文件
-
<cache>
(缓存):- 配置该 Mapper 对应的二级缓存。
eviction
属性:指定缓存的淘汰策略 (LRU, FIFO, SOFT, WEAK)。flushInterval
属性:指定缓存的刷新间隔 (毫秒)。size
属性:指定缓存的最大容量。readOnly
属性:指定缓存是否只读 (true
或false
)。<cache type="org.mybatis.cache.impl.PerpetualCache"/>
使用自定义缓存
-
<cache-ref>
(缓存引用):- 引用其他 Mapper 的缓存配置。
namespace
属性:指定要引用的 Mapper 的命名空间。
-
<resultMap>
(结果映射):-
作用: 定义如何将 SQL 语句的查询结果映射到 Java 对象。
-
id
属性:指定resultMap
的唯一标识。 -
type
属性:指定要映射的 Java 类型。 -
子元素:
<id>
:定义主键映射。property
属性:指定 Java 对象的属性名。column
属性:指定数据库表中的列名。
<result>
:定义普通属性映射。property
属性:指定 Java 对象的属性名。column
属性:指定数据库表中的列名。
<association>
:定义一对一关系映射。property
属性:指定 Java 对象的属性名。column
属性:指定数据库表中的列名。javaType
属性:指定关联对象的 Java 类型。select
属性:指定用于查询关联对象的 SQL 语句的 ID。
<collection>
:定义一对多关系映射。property
属性:指定 Java 对象的属性名。column
属性:指定数据库表中的列名。ofType
属性:指定集合中元素的 Java 类型。select
属性:指定用于查询集合元素的 SQL 语句的 ID。
<discriminator>
:定义鉴别器,根据不同的条件选择不同的映射规则。column
属性:指定用于鉴别的列名。<case>
元素:定义不同的映射规则。value
属性:指定鉴别值。resultMap
属性:指定要使用的resultMap
。
-
示例:
<resultMap id="UserResultMap" type="com.example.model.User"> <id property="id" column="id"/> <result property="username" column="username"/> <result property="email" column="email"/> <association property="address" column="address_id" javaType="com.example.model.Address" select="com.example.mapper.AddressMapper.selectAddressById"/> <collection property="orders" column="id" ofType="com.example.model.Order" select="com.example.mapper.OrderMapper.selectOrdersByUserId"/> </resultMap>
-
-
<select>
(查询):-
作用: 定义 SELECT 语句,用于查询数据。
-
id
属性:指定 SQL 语句的唯一标识。 与 Mapper 接口中的方法名对应。 -
parameterType
属性:指定参数类型。 -
resultType
属性:指定结果类型(如果使用简单类型映射)。 -
resultMap
属性:指定结果映射 (如果使用<resultMap>
元素)。 -
parameterMap
属性: (已经过时, 不建议使用) -
flushCache
属性: 如果设置为true
,则每次执行该语句都会刷新缓存。 -
useCache
属性:如果设置为true
,则该语句的结果会被缓存。 -
timeout
属性:设置超时时间(秒)。 -
fetchSize
属性:设置每次从数据库获取的记录数量。 -
statementType
属性: 指Statement类型, 可选值为 STATEMENT、PREPARED 和 CALLABLE。- STATEMENT, 默认值, 使用Statement
- PREPARED, 使用PreparedStatement, 可以防止SQL注入, 性能更好。
- CALLABLE, 主要用于执行存储过程
-
示例:
<select id="selectUserById" parameterType="int" resultMap="UserResultMap" useCache="true"> SELECT * FROM user WHERE id = #{id} </select>
-
-
<insert>
(插入):-
作用: 定义 INSERT 语句,用于插入数据。
-
id
属性:指定 SQL 语句的唯一标识。 -
parameterType
属性:指定参数类型。 -
useGeneratedKeys
属性:是否允许 MyBatis 使用 JDBC 的getGeneratedKeys
方法获取自增主键值。 -
keyProperty
属性:指定 Java 对象的哪个属性用于接收自增主键值。 -
keyColumn
属性:指定数据库表的主键列名. -
示例:
<insert id="insertUser" parameterType="com.example.model.User" useGeneratedKeys="true" keyProperty="id" keyColumn="id"> INSERT INTO user (username, email) VALUES (#{username}, #{email}) </insert>
-
-
<update>
(更新):-
作用: 定义 UPDATE 语句,用于更新数据。
-
id
属性:指定 SQL 语句的唯一标识。 -
parameterType
属性:指定参数类型。 -
示例:
<update id="updateUser" parameterType="com.example.model.User"> UPDATE user SET username = #{username}, email = #{email} WHERE id = #{id} </update>
-
-
<delete>
(删除):-
作用: 定义 DELETE 语句,用于删除数据。
-
id
属性:指定 SQL 语句的唯一标识。 -
parameterType
属性:指定参数类型。 -
示例:
<delete id="deleteUserById" parameterType="int"> DELETE FROM user WHERE id = #{id} </delete>
-
-
<sql>
(SQL 片段):-
作用: 定义可以重复使用的 SQL 代码片段。
-
id
属性:指定 SQL 片段的唯一标识。 -
示例:
<sql id="userColumns"> id, username, email </sql>
-
四、 动态 SQL 元素 (Dynamic SQL Elements)
MyBatis 提供了以下动态 SQL 元素,可以根据不同的条件动态生成 SQL 语句:
-
<if>
:-
作用: 根据条件判断是否包含某段 SQL 代码。
-
test
属性:指定判断条件,使用 OGNL 表达式。 -
示例:
<select id="selectUserByCondition" parameterType="com.example.model.User" resultMap="UserResultMap"> SELECT * FROM user <where> <if test="username != null and username != ''"> AND username = #{username} </if> <if test="email != null and email != ''"> AND email = #{email} </if> </where> </select>
-
-
<choose>
,<when>
,<otherwise>
:-
作用: 类似于 Java 中的
switch-case
语句,用于选择其中一个条件分支。 -
<choose>
元素:包含多个<when>
元素和一个<otherwise>
元素。 -
<when>
元素:指定条件和对应的 SQL 代码。 -
<otherwise>
元素:指定默认的 SQL 代码(当所有<when>
条件都不满足时执行)。 -
test
属性:指定<when>
元素的判断条件,使用 OGNL 表达式。 -
示例:
<select id="selectUserByCondition" parameterType="com.example.model.User" resultMap="UserResultMap"> SELECT * FROM user <where> <choose> <when test="username != null and username != ''"> AND username = #{username} </when> <when test="email != null and email != ''"> AND email = #{email} </when> <otherwise> AND 1 = 1 </otherwise> </choose> </where> </select>
-
-
<where>
:-
作用: 动态生成
WHERE
子句,并自动处理AND
或OR
关键字。 -
如果
<where>
元素内部有任何内容,它会自动添加WHERE
关键字。 -
如果
<where>
元素内部的内容以AND
或OR
开头,它会自动移除这些关键字。 -
示例:
<select id="selectUserByCondition" parameterType="com.example.model.User" resultMap="UserResultMap"> SELECT * FROM user <where> <if test="username != null and username != ''"> AND username = #{username} </if> <if test="email != null and email != ''"> AND email = #{email} </if> </where> </select>
-
-
<set>
:-
作用: 动态生成
SET
子句,用于 UPDATE 语句,并自动处理逗号,
。 -
如果
<set>
元素内部有任何内容,它会自动添加SET
关键字。 -
如果
<set>
元素内部的内容以逗号,
开头,它会自动移除这个逗号。 -
示例:
<update id="updateUserSelective" parameterType="com.example.model.User"> UPDATE user <set> <if test="username != null"> username = #{username}, </if> <if test="email != null"> email = #{email}, </if> </set> WHERE id = #{id} </update>
-
-
<trim>
:-
作用: 更通用的动态 SQL 元素,可以自定义前缀、后缀、以及前缀和后缀要移除的内容。
-
prefix
属性:指定前缀。 -
suffix
属性:指定后缀。 -
prefixOverrides
属性:指定要移除的前缀。 -
suffixOverrides
属性:指定要移除的后缀。 -
示例:
<select id="selectUserByCondition" parameterType="com.example.model.User" resultMap="UserResultMap"> SELECT * FROM user <trim prefix="WHERE" prefixOverrides="AND |OR"> <if test="username != null and username != ''"> AND username = #{username} </if> <if test="email != null and email != ''"> AND email = #{email} </if> </trim> </select> <update id="updateUserSelective" parameterType="com.example.model.User"> UPDATE user <trim prefix="SET" suffixOverrides=","> <if test="username != null"> username = #{username}, </if> <if test="email != null"> email = #{email}, </if> </trim> WHERE id = #{id} </update>
-
-
<foreach>
:-
作用: 用于遍历集合,生成重复的 SQL 代码。
-
collection
属性:指定要遍历的集合。 -
item
属性:指定集合中元素的别名。 -
index
属性:指定当前元素的索引的别名。 -
open
属性:指定循环开始时的字符串。 -
close
属性:指定循环结束时的字符串。 -
separator
属性:指定元素之间的分隔符。 -
示例:
<select id="selectUsersByIds" parameterType="list" resultMap="UserResultMap"> SELECT * FROM user WHERE id IN <foreach item="id" collection="list" open="(" separator="," close=")"> #{id} </foreach> </select> <insert id="insertUsers" parameterType="list"> INSERT INTO user (username, email) VALUES <foreach item="user" collection="list" separator="," > (#{user.username}, #{user.email}) </foreach> </insert>
-
-
<bind>
:- 作用: 创建一个变量,并将其绑定到 OGNL 表达式的结果。
name
属性: 指定变量名value
属性: 指定 OGNL 表达式- 示例:
<select id="selectUsersBySearchTerm" parameterType="string" resultMap="UserResultMap"> <bind name="pattern" value="'%' + searchTerm + '%'" /> SELECT * FROM user WHERE username LIKE #{pattern} OR email LIKE #{pattern} </select>
五、 DOCTYPE (Document Type Definition)
MyBatis SQL 映射文件需要遵循特定的 DTD 约束.
-
DTD 声明:
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
-
DTD 文件:
mybatis-3-mapper.dtd
文件定义了 MyBatis SQL 映射文件的结构。可以在 MyBatis 的官方网站上找到该文件。- 开发中通常不需要我们手动修改 DTD 文件,只需要在 XML 配置文件中声明 DTD 即可。
六、总结
MyBatis SQL 映射文件是 MyBatis 框架的核心,它定义了 SQL 语句以及如何将 SQL 语句的参数和结果映射到 Java 对象。