动态SQL
动态 SQL 是 MyBatis 的一个强大的特性。有以下几个特点:
- 根据不同的条件需要执行不同的 SQL 命令,称为动态 SQL
- MyBatis 通过 OGNL 表达式来进行动态SQL的使用。
- MyBatis 中动态 SQL 在 mapper.xml 中添加逻辑判断等。
常用标签
元素 | 作用 |
if | 实现简单的条件选择,判断语句 |
choose(when,otherwise) | 相当于 Java 中的 switch 语句,通常与 when 和 otherwise 搭配使用 |
where | 简化 SQL 语句中 where 的条件判断 |
set | 解决动态更新语句 |
trim | 可以灵活去除多余的关键字 |
foreach | 迭代一个集合,通常用于 in 条件 |
bind | 创建一个变量,并绑定到上下文 |
1、 if 标签
1.1 在 were 条件中使用 if 标签(查询)
if 标签是我们最常使用的。必须结合 test 属性联合使用。
- 这个 SQL 中,使用了where 1=1,这是多条件拼接的小技巧,后面的条件查询就可以都用 and 了。
- if 标签的 test 属性值是一个符合 OGNL 的表达式,表达式可以是 true 或 false。如果表达式返回的是数值,则 0 为 false,非 0 为 true。
1.1.1 mapper
UserMapper.java
/**
* 通过姓名进行模糊查询
* @param user
* @return
*/
List<User> selectUserByName(User user);UserMapper.xml
如果 name 为 null,则查询全部,否则模糊查询
<select id="selectUserByName" parameterType="User" resultType="User">
select * from user where 1=1
<if test="name != null">
and name like concat('%', #{name},'%')
</if>
</select>1.1.2 测试
@org.junit.Test
public void selectUserByNameTest(){
SqlSession session = factory.openSession();
UserMapper userMapper = session.getMapper(UserMapper.class);
User user = new User();
// 查询所有
List<User> list = userMapper.selectUserByName(user);
System.out.println(list);
// 模糊查询
user.setName("yu1");
List<User> userList = userMapper.selectUserByName(user);
System.out.println(userList);
session.commit();
session.close();
}1.1.3 测试结果
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-mSQqShlE-1602291919154)(…/…/…/…/noteImage/image-20201009150011561.png)]
1.2 insert 动态插入中使用 if 标签
在我们插入数据库中的记录中,不是每一个字段都有值的,这个时候可以通过 if 标签来判断字段是否有值。
1.2.1 mapper
UserMapper.java
/**
* 非空字段才进行插入
* @param user
* @return
*/
public int insertUser(User user);UserMapper.xml
<insert id="insertUser" parameterType="User">
insert into user
<trim prefix="(" suffix=")" suffixOverrides=",">
<if test="name != null">
name,
</if>
<if test="password != null">
password,
</if>
<if test="phone != null">
phone,
</if>
<if test="sex != null">
sex,
</if>
<if test="birthday != null">
birthday,
</if>
</trim>
<trim prefix="values (" suffix=")" suffixOverrides=",">
<if test="name != null">
#{name},
</if>
<if test="password != null">
#{password},
</if>
<if test="phone != null">
#{phone},
</if>
<if test="sex != null">
#{sex},
</if>
<if test="birthday != null">
#{birthday},
</if>
</trim>
</insert>1.2.2 测试
@org.junit.Test
public void insertUserTest(){
SqlSession session = factory.openSession();
UserMapper userMapper = session.getMapper(UserMapper.class);
User user = new User();
user.setName("xiaoyu");
user.setPassword("xiaoyu");
user.setBirthday(new Date());
user.setPhone("15870934313");
user.setSex("男");
System.out.println(userMapper.insertUser(user));
session.commit();
session.close();
}1.2.3 运行结果
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-XjHV6dI3-1602291919158)(…/…/…/…/noteImage/image-20201009143802695.png)]
2、where 标签
- 当编写where标签时,如果内容中第一个是and就会去掉第一个and,
- 如果where标签中有内容会生成where关键字,如果没有内容不会生成where关键字
- 比直接使用if少写了where 1=1
2.1 mapper
List<User> selectUserByNameTag(User user);<select id="selectUserByNameTag" parameterType="User" resultType="User">
select * from user
<where>
<if test="name != null">
and name like concat('%', #{name},'%')
</if>
</where>
</select>2.2 测试
@org.junit.Test
public void selectUserByNameTest2(){
SqlSession session = factory.openSession();
UserMapper userMapper = session.getMapper(UserMapper.class);
User user = new User();
// 查询所有
List<User> list = userMapper.selectUserByNameTag(user);
System.out.println(list);
// 模糊查询
user.setName("yu1");
List<User> userList = userMapper.selectUserByNameTag(user);
System.out.println(userList);
session.commit();
session.close();
}2.3 测试结果
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-G6IOBSJw-1602291919161)(…/…/…/…/noteImage/image-20201009151650994.png)]
3、choose、when、otherwise标签
- 只要有一个成立,其他都不成立
- 代码示例
<select id="selectByNameAndPassword" resultType="User">
select * from user
<where>
<choose>
<when test="name != null">
and name = #{name}
</when>
<when test="password != null">
and password = #{password}
</when>
</choose>
</where>
</select>4、set标签
- 作用,去掉最后一个逗号
- 作用:如果里面有内容生成set关键字,没有就不生成。
当更新时传入空值时,可以将空值不更新
4.1 mapper
/**
* 更新用户
* @param user
* @return
*/
int updateUser(User user);<update id="updateUser" parameterType="User">
update user
<set>
<if test="name != null">
name = #{name},
</if>
<if test="password != null">
password = #{password},
</if>
<if test="phone != null">
phone = #{phone},
</if>
<if test="sex != null">
sex = #{sex},
</if>
<if test="birthday != null">
birthday = #{birthday},
</if>
</set>
where id = #{id}
</update>4.2 测试
@org.junit.Test
public void updateUserTest(){
SqlSession session = factory.openSession();
UserMapper userMapper = session.getMapper(UserMapper.class);
User user = new User();
user.setId(2);
user.setName("xiaoyu7");
user.setPassword("xiaoyu7");
user.setBirthday(new Date());
user.setPhone("15870934313");
user.setSex("男");
System.out.println(userMapper.updateUser(user));
session.commit();
session.close();
}4.3 测试结果
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-FJSePBjc-1602291919165)(…/…/…/…/noteImage/image-20201009150919570.png)]
5、trim标签
前面 1.1 里面使用了 trim,这里介绍一下用法。
5.1 trim 用来表示 where
<trim prefix="where" prefixOverrides="AND | OR"></trim>表示当 trim 里面有内容时,添加 where ,且第一个为 AND 或 OR 时,会将其去掉,而如果没有内容,则不添加 where。
5.2 trim 用来表示 set
<trim prefix="set" suffixOverrides=","></trim>表示当 trim 里面有内容时,添加 set ,且最后的内容为 , 时,会将其去掉,而如果没有内容,则不添加 set。
5.3 trim 的属性
- prefix:在前面添加内容
- prefixOverrides :去掉前面的内容
- suffix :在后面添加内容
- suffixOverrides :去掉后面内容
- 执行顺序是去掉内容后添加内容
6、bind标签
- 作用:通过 OGNL 表达式去定义一个上下文的变量
- 场景:
- 模糊查询
- 在原内容前或后添加内容
- 示例
<select id="selectByLog" resultType="User" parameterType="User">
<bind name="name" value="'%' + name + '%'"/>
select * from user where name like #{name}
</select>7、foreach标签
- 循环参数内容,还具备在内容的前后添加内容,还具备添加分隔符的功能
- 适用场景:in查询。批量新增中(mybatis中foreach效率比较低)
- 如果希望批量新增,SQL命令
- openSession()必须指定
- 底层是JDBC的PreparedStatement.addBatch();
- 示例
- collection="" :要遍历的集合
- item="" :迭代变量,#{迭代变量名} 获取内容
- open="" :循环后左侧添加的内容
- close="" :循环后右侧添加的内容
- separator="" :循环分隔符
- index:索引的属性名。当迭代对象为 Map 时,该值为 Map 中的 Key。
<select id="selectIn" parameterType="list" resultType="User">
select * from user where name in
<foreach collection="list" item="abc" open="(" close=")" separator=",">
#{abc}
</foreach>
</select>- 和
- 某些SQL片段如果希望复用,可以使用定义这个片段
- 在、、、中使用引用
<select id="select">
select <include refid="mysql"></include>
from user
</select>
<sql id="mysql">
id,name,passowrd,sex,phone,birthday
</sql>
















