动态SQL
动态 SQL 是 MyBatis 的强大特性之一。如果你使用过 JDBC 或其它类似的框架,你应该能理解根据不同
条件拼接 SQL 语句有多痛苦,例如拼接时要确保不能忘记添加必要的空格,还要注意去掉列表最后一个
列名的逗号。利用动态 SQL,可以彻底摆脱这种痛苦。
使用动态 SQL 并非一件易事,但借助可用于任何 SQL 映射语句中的强大的动态 SQL 语言,MyBatis 显
著地提升了这一特性的易用性。
if
用于进行条件判断, test 属性用于指定判断条件. 为了拼接条件, 在 SQL 语句后强行添加 1=1 的恒成立条件
<select id="sel" resultType="user">
select * from t_user where 1=1
<if test="username != null and username != ''"> and username=#{username}
</if>
<if test="password != null and password != ''"> and password=#{password}
</if>
</select>
<select id="findUserById" resultType="user">
select * from user where
<if test="id != null">
id=#{id}
</if>
and deleteFlag=0;
</select>
where
用于管理 where 子句. 有如下功能:
- 如果没有条件, 不会生成 where 关键字
- 如果有条件, 会自动添加 where 关键字
- 如果第一个条件中有 and, 去除之
<select id="sel" resultType="user">
select * from t_user
<where>
<if test="username != null and username != ''"> and username=#{username}
</if>
<if test="password != null and password != ''"> and password=#{password}
</if>
</where>
</select>
<select id="findUserById" resultType="user">
select * from user
<where>
<if test="id != null">
id=#{id}
</if>
and deleteFlag=0;
</where>
</select>
choose…when…otherwise
<select id="sel" resultType="user">
select * from t_user
<where>
<choose>
<when test="username != null and username != ''">
and username = #{username}
</when>
<when test="password != null and password != ''">
and password = #{password}
</when>
<otherwise> and 1=1 </otherwise>
</choose>
</where>
</select>
set
用于维护 update 语句中的 set 子句. 功能如下:
- 满足条件时, 会自动添加 set 关键字
- 会去除 set 子句中多余的逗号
- 不满足条件时, 不会生成 set 关键字
int updUser(User user);
<update id="updUser" parameterType="user">
update t_user
<set>
id=#{id},<!-- 防止所有条件不成立时的语法错误 -->
<if test="username != null and username != ''">
username=#{username},
</if>
<if test="password != null and password != ''">
password=#{password},
</if>
</set>
where id=#{id}
</update>
<update id="updateUser" parameterType="com.dy.entity.User">
update user set
<if test="name != null">
name = #{name},
</if>
<if test="password != null">
password = #{password},
</if>
<if test="age != null">
age = #{age}
</if>
<where>
<if test="id != null">
id = #{id}
</if>
and deleteFlag = 0;
</where>
</update>
trim
用于在前后添加或删除一些内容
- prefix, 在前面添加内容
- prefixOverrides, 从前面去除内容
- suffix, 向后面添加内容
- suffixOverrides, 从后面去除内容
<update id="updUser" parameterType="user">
update t_user
<!-- prefix: 前缀, 表示向前面添加内容 prefixOverrides: 从前面删除内容 suffix: 后缀,
表示向后面添加内容 suffixOverrides: 从后面删除内容 -->
<trim prefix="set" prefixOverrides="user" suffix="hahaha"
suffixOverrides=","> username=#{username},
</trim>
where id=#{id}
</update>
<!--********************************************-->
<trim prefix="WHERE" prefixOverrides="AND |OR ">
...
</trim>
bind
用于对数据进行再加工, 用于模糊查询
<select id="sel" resultType="user">
select * from t_user
<where>
<if test="username!=null and username!=''">
<bind name="username" value="'%' + username + '%'" />
and username like #{username}
</if>
</where>
</select>
foreach
用于在 SQL 语句中遍历集合参数, 在 in 查询中使用
- collection: 待遍历的集合
- open: 设置开始符号
- item: 迭代变量
- separator: 项目分隔符
- close: 设置结束符
List<User> selIn(@Param("list") List<Integer> list);
<select id="selIn" parameterType="list" resultType="user">
select * from t_user where id in
<foreach collection="list" open="(" separator="," close=")"
item="item"> #{item} </foreach>
</select>
sql…include
sql用于提取 SQL 语句, include用于引用 SQL 语句
<sql id="mySql"> id, username, password </sql>
<select id="selIn" parameterType="list" resultType="user">
select
<include refid="mySql" />
from t_user where id in
<foreach collection="list" open="(" separator="," close=")"
item="item"> #{item}
</foreach>
</select>
列名和属性名不一致问题
如果查询时使用 resultType 属性, 表示采用 MyBatis 的Auto-Mapping(自动映射)机制, 即相同的列名和属性名会自动匹配. 因此, 当数据库表的列名和类的属性名不一致时, 会导致查不到数据. 解决该问题可以有两种方式:
列别名
查询时, 可以通过列别名的方式将列名和属性名保持一致,继续使用自动映射, 从而解决该问题. 但是较为麻烦.
<select id="selAll" resultType="user">
select id id1, username username1, password password2 from t_user
</select>
使用resultMap
resultMap用于自定义映射关系, 可以由程序员自主制定列名和属性名的映射关系. 一旦使用 resultMap,表示不再采用自动映射机制.
<resultMap type="user" id="umap"> <!-- id用于映射主键 -->
<id column="id" property="id1" /> <!-- 非主键使用result映射 -->
<result column="username" property="username1" />
<result column="password" property="password1" />
</resultMap>
<select id="selAll" resultMap="umap"> select * from t_user </select>
关系映射查询
数据库中表与表之间的关系:
一对一 (人->身份证)
一对多 (夏令营->学生)
多对一 (学生->班级)
多对多 (学生->课程)
resultMap 的关联方式实现多表查询(一对一|多对一)
- 在 StudentMapper.xml 中定义多表连接查询 SQL 语句, 一次性查到需要的所有数据, 包括对应班级的信息.
- 通过resultMap标签定义映射关系, 并通过association标签指定对象属性的映射关系. 可以把association标签看成一个resultMap标签使用. javaType 属性表示当前对象, 可以写全限定路径或别名.
学生类中添加一个班级类型的属性 :
public class Student implements Serializable{
private int id;
private String name;
private int age;
private String gender;
private int cid;
private Clazz cls;
}
StudentMapper:
<resultMap type="student" id="smap">
<id property="id" column="sid" />
<result property="name" column="sname" />
<result property="age" column="age" />
<result property="gender" column="gender" />
<result property="cid" column="cid" />
<association property="cls" javaType="clazz">
<id property="id" column="cid" />
<result property="name" column="cname" />
<result property="room" column="room" />
</association>
</resultMap>
<select id="selAll" resultMap="smap">
select s.id sid, s.name sname,
s.age, s.gender, c.id cid, c.name cname, c.room from t_student s left
join t_class c on s.cid=c.id
</select>
resultMap 的关联方式实现多表查询(一对 多)
- 在 ClazzMapper.xml 中定义多表连接查询 SQL 语句, 一次性查到需要的所有数据, 包括对应学生的信息.
- 通过resultMap定义映射关系, 并通过collection标签指定集合属性泛型的映射关系. 可以collection标签看成一个resultMap标签使用. ofType 属性表示集合的泛型, 可以写全限定路径或别名.
班级类中添加一个List容器存储学生类型 的数据 :
public class Clazz implements Serializable{
private int id;
private String name;
private int roomNum;
private List<Student> stus;
}
ClazzMapper.xml:
<mapper namespace="com.xxxx.mapper.ClazzMapper">
<resultMap type="clazz" id="cmap">
<id property="id" column="cid" />
<result property="name" column="cname" />
<result property="room" column="room" />
<collection property="stus" javaType="list"
ofType="student">
<id property="id" column="sid" />
<result property="name" column="sname" />
<result property="age" column="age" />
<result property="gender" column="gender" />
<result property="cid" column="cid" />
</collection>
</resultMap>
<select id="selAll" resultMap="cmap">
select c.id cid, c.name cname,
c.room, s.id sid, s.name sname, s.age, s.gender from t_student s right
join t_class c on s.cid=c.id </select>
</mapper>