文章目录
MyBatis 映射文件标签
映射文件要和接口文件名称相同。
ORM(Object Relationship Mapping)对象关系映射。
对象代表 Java 实体类对象,关系代表关系型数据库,映射代表二者之间的对应关系。
下面将对 MyBatis XML 映射文件的常用标签进行总结:
一、定义SQL语句
共有4个标签,分别是insert、delete、update、select,对应增删改查。其中,select 标签的使用频率最高。具体使用如下:
Mapper 层接口定义方法如下:
public interface StudentMapper {
Student findById(Integer id);
List<Student> findAll();
}
Mapper.XML 映射文件如下:
<?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.exercise.dao.StudentMapper">
<select id="fingById" resultType="com.exercise.entity.Student">
<!-- Mybatis负责把SQL语句中的#{}部分替换成“?”占位符,在#{}内部还是要声明一个见名知意的名称 -->
select * from t_student where id = #{id}
</select>
<select id="findAll" resultType="com.exercise.entity.Student">
select * from user
</select>
</mapper>
说明:
- mapper 是根标签,namespace 属性设置为接口的全类名。
- 标签中的 id 属性是接口方法的方法名,id 是唯一的,即标记一条 SQL 语句。
- 标签中的 resultType 属性是接口方法的返回值类型,格式为全类名,如果是集合类型,则写其泛型的全类名。
- 标签中的 parameterType 属性是接口方法的参数类型,格式为全类名,如果是集合类型,则写其泛型的全类名。
- 参数/返回值类型为基本数据类型/包装类/String等类型时,我们可以写全类名,也可以写别名。MyBatis 内置的类型别名如下:
映射的类型 | 别名 | 映射的类型 | 别名 |
---|---|---|---|
byte | _byte | String | string |
long | _long | Byte | byte |
short | _short | Long | long |
int | _int | Short | short |
int | _integer | Integer | integer\int |
double | _double | Double | double |
float | _float | Float | float |
boolean | _boolean | Boolean | boolean |
Map | map | Date | date |
HashMap | hashmap | BigDecimal | decimal |
List | list | BigDecimal | bigdecimal |
ArrayList | arraylist | Object | obkect |
Collection | collection | Iterator | iterator |
二、自定义映射关系
MyBatis 可以将数据库结果集封装到对象中,是因为结果集的列名和对象属性名相同。当 Entity 属性名和数据库列名不一致时,MyBatis 无法自动完成映射
关系。此时有两种解决方案:
- SQL 语句的查询字段起与 Entity 属性相同的别名。
- 自定义映射关系,使用
<resultMap>
标签定义对应关系,再在后面的SQL语句中引用这个对应关系
实际开发中使用第二种方式居多,具体如下:
<resultMap id="selectStudentMap" type="com.exercise.entity.Student">
<id column="id" property="studentId"/>
<result column="name" property="studentName"/>
<result column="class" property="studentClass"/>
</resultMap>
<select id="selectStudent" resultMap="selectStudentMap">
select id,name,class from t_student where id=#{id}
</select>
说明:
- resultMap 标签中的 id 属性为自定义映射名,type 属性为自定义映射的对象(实际开发中一般为一个 DTO 或者 VO)。
- id 标签设置主键列和主键属性之间的对应关系,column 属性代表数据库字段名,property 属性代表 Java 实体类属性名。
- result 标签设置普通字段和 Java 实体类属性之间的关系,column 和 property 属性与 id 标签一致。
三、动态SQL拼接
1. if 标签
使用<if>
标签,让我们可以有选择的加入 SQL 语句的片段。标签内的Sql片段在满足条件后才会添加,具体如下:
<select id="selectByCondition" parameterType="com.exercise.entity.Student" resultType="com.exercise.entity.Student">
select * from t_student
<where>
<if test="id != null">
id = #{id}
</if>
<if test="name != null and name.length() != 0">
and name like concat('%',#{name},'%')
</if>
<if test="class != null and class.length() != 0">
and class = #{class}
</if>
</where>
</select>
说明:
- if 标签中的 test 属性代表条件,满足则加入 SQL 片段,反之则不加入。
- if 中的条件可以直接通过属性名获取参数 Entity 的属性值,并且该值可以调用方法,例如 String.length(),不能访问数据库表的字段。
- if 中的条件不能使用 &&/|| ,而应该使用 and/or。
2. foreach 标签(重要)
<foreach>
标签可以遍历集合或者数组,在实际开发中非常实用。它主要有以下属性:
- collection 属性:遍历的集合对象
- item 属性:表示本次遍历获取的元素(设置名字,便于后面引用),遍历 List、Set、数组时表示每项元素,遍历 Map 时表示键值对的值。
- index 属性:遍历 List、数组时表示遍历的索引,遍历 Map 时表示键值对的键。
- separator 属性:遍历每项元素间的分隔符。
- open 属性:拼接字符串的前缀。
- close 属性:拼接字符串的后缀。
此处放一个遇见的实际场景,单表查询(表、查询字段、查询字段值、附加条件都为动态获取),具体例子如下:
Dao 层接口方法如下:
/**
* 单表查询
* @param tableName 表名
* @param queryPrimaryKeyList 查询主键集合(注:设计集合的形式是因为还有多表联查)
* @param queryPrimaryKeyValueList 查询主键集合(附带value)
* @param queryFieldList 查询字段集合(注:查询字段里面不包含查询主键)
* @param extraFieldList 附加条件集合
* @return
*/
List<Map<String,Object>> queryDataResultSingleTable(@Param("tableName") String tableName,
@Param("queryPrimaryKeyList") List<String> queryPrimaryKeyList,
@Param("queryPrimaryKeyValueList") List<Map<String, Object>> queryPrimaryKeyValueList,
@Param("queryFieldList") List<String> queryFieldList,
@Param("extraFieldList") List<ExtraFieldDTO> extraFieldList);
Mapper.XML 映射文件如下:
<select id="queryDataResultSingleTable" resultType="map">
SELECT
<foreach collection="queryPrimaryKeyList" item="queryPrimaryKey" index="index" separator=",">
${queryPrimaryKey}
</foreach>,
<foreach collection="queryFieldList" item="queryField" index="index" separator=",">
${queryField}
</foreach>
FROM
${tableName}
<where>
<foreach collection="queryPrimaryKeyValueList" item="queryPrimaryKey" >
<foreach collection="queryPrimaryKey.entrySet()" item="value" index="key">
OR ${key} = #{value}
</foreach>
</foreach>
<if test="extraFieldList!= null and extraFieldList.size()>0 ">
<foreach collection="extraFieldList" item="extraField">
<foreach collection="extraField.entrySet()" item="value" index="key">
AND ${key} like concat('%',#{value,jdbcType=VARCHAR},'%')
</foreach>
</foreach>
</if>
</where>
</select>
3. choose/when/otherwise 标签
这三个标签表示多条件分支,即在多个分支条件中,仅执行一个。类似于 Java 中的 switch…case 语句,<choose>
类似于 switch 关键字,<when>
类似于 case 关键字,<otherwise>
类似于 default 关键字。执行流程如下:
- 从上到下依次进行条件判断。
- 判断到第一个满足条件的分支会被执行。
- 被执行后后面的分支都不会执行。
- 如果所有的 when 分支都不满足,即执行 otherwise 分支中的语句。
具体举例如下:
<!-- 含义为名字长度<3时使用模糊查询,名字长度>=3并且<5时使用精确查询,否则查询id为1的用户 -->
<select id="selectByCondition" resultType="com.exercise.entity.Student" parameterType="com.exercise.entity.Student">
select * from t_student
<where>
<choose>
<when test="name.length()< 3">
name like concat('%',#{value},'%')
</when>
<when test="name.length()< 5">
name = #{name}
</when>
<otherwise>
id = 1
</otherwise>
</choose>
</where>
</select>
说明:在 MyBatis 映射文件中尽量不要使用一些特殊字符,如:<,>等。我们可以使用符号的实体来表示,具体如下:
符号 | 实体 |
---|---|
< | <; |
> | >; |
& | &; |
’ | &apos; |
‘’ | "; |
四、格式化输出
1. where 标签
<where>
标签可以自动去掉标签体内多余的 and 和 or 。此标签一般配合 if 标签使用,试想一下,如果我们使用 if 标签,就需要加入 where 关键字,当所有的 if 条件都不满足或者从第二个条件开始满足,这时我们输出的 SQL 语句就是错误的。由于在前面标签的举例中一直在使用 where 标签,此处就不做具体举例了。
2. set 标签
在实际开发中,对于一个实体类对象进行更新,往往不是更新所有字段,而是更新用户更改的一部分字段。<set>
标签用在 update 语句中,借助 <if>
标签,可以只对有具体值的字段进行更新。<set>
标签会自动添加 set 关键字,并且动态去掉两端多余的逗号。具体举例如下:
<update id="updateById" parameterType="com.exercise.entity.Student">
update user
<set>
<if test="name != null and name.length() > 0">
name = #{name},
</if>
<if test="class != null and class.length() > 0">
class = #{class},
</if>
</set>
<where>
id = #{id}
</where>
</update>
3. trim 标签
<trim>
标签可以控制条件部分两端是否包含某些字符,它主要有以下属性:
- prefix 属性:指定要动态添加的前缀
- suffix 属性:指定要动态添加的后缀
- prefixOverrides 属性:指定要动态去掉的前缀,使用"|"分隔有可能的多个值
- suffix Overrides 属性:指定要动态去掉的后缀,使用"|"分隔有可能的多个值
五、配置关联关系
1. association 标签
使用<association>
标签可以配置一对一关联关系,它有以下属性,具体如下:
- property 属性:引用时使用的属性名
- javaTyoe 属性:对应的全类名
具体举例如下:
<resultMap id="studentMap" type="com.exercise.entity.Student">
<id column="id" property="id"></id>
<result column="name" property="name"></result>
<!-- 一对一对象列 property:属性名 javaType:对象类型-->
<association property="class" javaType="com.exercise.entity.Class">
<id column="class_id" property="classId"></id>
<result column="class_name" property="className"></result>
</association>
</resultMap>
<!-- 多表查询,级联查询学生和其班级 -->
<select id="findAll" resultMap="studentMap">
select * from t_student left join t_class on student.classId = class.class_id
</select>
2. collection 标签
使用<collection>
标签可以配置一对多关联关系,它有一下属性,具体如下:
- property 属性:关联“多”的一端的属性名
- ofTyoe 属性:集合属性中元素的类型
具体举例如下:
<resultMap id="classesMap" type="com.exercise.entity.Class">
<id column="class_id" property="classId"></id>
<result column="class_name" property="className"></result>
<!-- 集合列 property:属性名 ofType:集合的泛型 -->
<collection property="studentList" ofType="com.exercise.entity.Student">
<id column="id" property="id"></id>
<result column="name" property="name"></result>
</collection>
</resultMap>
<!-- 多表查询,级联查询班级和它的学生 -->
<select id="selectAllStudent" resultMap="classesMap">
select * from t_class left join t_student on class.class_id = student.classId;
</select>
六、定义常量及引用
<sql>
标签可以用来定义可重用的 SQL 片段,然后通过 <include>
标签引入该片段。具体使用如下:
<sql id="selectAllField">
select id as studentId, name as studentName
</sql>
<select id="selectById" resultType="com.exercise.entity.Student">
<include refid="selectAllField"></include>
from t_student where id = #{id}
</select>