项目目录
动态 SQL 之if标签
持久层 Dao 接口
/**
* 根据传入的参数条件
* @param user 查询的条件,有可能有用户名 ,性别,或都没有
* @return
*/
List<User> finduserCondition(User user);
持久层 Dao 映射配置
这里使用#{},预编译指令,代替SQL语句中?,可以有效防止SQL注入
<!--根据条件查询-->
<select id="finduserCondition" resultMap="userMap" parameterType="user">
select * from user where 1=1
<if test="userName != null">
and username = #{userName}
</if>
<if test="userSex != null">
and sex = #{userSex}
</if>
</select>
测试代码
/**
* 根据条件查询 if标签
* @throws Exception
*/
@Test
public void testfinduserCondition() throws Exception {
User u = new User();
u.setUserName("老王");
u.setUserSex("男");
//5.使用代理对象执行方法
List<User> users = userDao.finduserCondition(u);
for (User user : users) {
System.out.println(user);
}
}
测试结果:
动态 SQL 之where标签
为了简化上面 where 1=1 的条件拼装,我们可以采用标签来简化开发。
持久层 Dao 映射配置
<select id="finduserCondition" resultMap="userMap" parameterType="user">
select * from user
<where>
<if test="userName != null">
and username = #{userName}
</if>
<if test="userSex != null">
and sex = #{userSex}
</if>
</where>
</select>
效果和上面的if标签一样
动态 SQL 之foreach标签
传入多个 id 查询用户信息,用下边两个 sql 实现:
SELECT * FROM USERS WHERE username LIKE ‘%王%’ AND (id =10 OR id =19 OR id=36)
SELECT * FROM USERS WHERE username LIKE ‘%王%’ AND id IN (10,19,36)
这样我们在进行范围查询时,就要将一个集合中的值,作为参数动态添加进来。
在 QueryVo 中加入一个 List 集合用于封装参数
QueryVo:
package com.keafmd.domain;
import java.util.List;
public class QueryVo {
private User user;
private List<Integer> ids;
public List<Integer> getIds() {
return ids;
}
public void setIds(List<Integer> ids) {
this.ids = ids;
}
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
}
持久层 Dao 接口
/**
* 根据QueryVo中提供的id集合查询
* @param vo
* @return
*/
List<User> findUserInIds(QueryVo vo);
持久层 Dao 映射配置
<!--根据QueryVo中的id集合实现查询查询用户列表-->
<select id="findUserInIds" resultMap="userMap" parameterType="queryvo">
<include refid="defaultUser"></include>
<where>
<if test="ids!=null and ids.size()>0">
<foreach collection="ids" open = "and id in (" close=")" item="uid" separator=",">
#{uid}
</foreach>
</if>
</where>
</select>
测试代码
@Test
public void testfindUserInIds() throws Exception {
QueryVo vo = new QueryVo();
List<Integer> list = new ArrayList<Integer>();
list.add(41);
list.add(42);
list.add(50);
vo.setIds(list);
//5.使用代理对象执行方法
List<User> users = userDao.findUserInIds(vo);
for (User user : users) {
System.out.println(user);
}
}
测试结果:
Mybatis中简化编写的 SQL 片段
Sql 中可将重复的 sql 提取出来,使用时用 include 引用即可,最终达到 sql 重用的目的。
这样可以简化我们每次都需要在sql语句中写的select * from user。
定义代码片段
<!--了解的内容,抽取重复的sql语句-->
<sql id="defaultUser">
select * from user
</sql>
注意细节:在抽取重复的sql语句尽量不要写分号;因为可能还会和后面的sql语句进行拼接,有分号就会导致报错。
引用代码片段
<!--配置查询所有-->
<select id="findAll" resultMap="userMap">
<include refid="defaultUser"></include>
</select>
<!--根据QueryVo中的id集合实现查询查询用户列表-->
<select id="findUserInIds" resultMap="userMap" parameterType="queryvo">
<include refid="defaultUser"></include>
<where>
<if test="ids!=null and ids.size()>0">
<foreach collection="ids" open = "and id in (" close=")" item="uid" separator=",">
#{uid}
</foreach>
</if>
</where>
</select>
注意:使用特殊转义字符情景
方法1:
例如,>=开始日期 并且<=结束日期
> 代替 > 大于号
< 代替 < 小于号
方法2:使用<![CDATA[ ]]>符号
<if test="beginTime!=null">
AND DATE (os.show_start_time) >= DATE(#{beginTime})
</if>
<if test="endTime!=null">
AND DATE (os.show_start_time) <![CDATA[<=]]> DATE(#{endTime})
</if>
在mybatis中<=不能使用,需要使用上面任意一种方法转义,但是>=可以使用!
动态sql的执行原理
总的来说
使用OGNL从SQL参数对象中解析表达式的值,再根据表达式值动态拼接SQL
具体步骤
1.首先解析xml配置文件,有一个createSqlSource操作
SqlSource sqlSource = langDriver.createSqlSource(configuration, context, parameterTypeClass)
2.createSqlSource底层使用了XMLScriptBuilder对xml中的标签解析
3.XMLScriptBuilder调用parseScriptNode方法的parseDynamicTags()对nodeHandlers里的标签根据不同的handler来处理不同的标签
4.然后把DynamicContext结果放回SqlSource中
5.DynamicSqlSource获取BoundSql,在Executor执行的时候,调用DynamicSqlSource的解析方法,并返回解析好的BoundSql,和已经排好序,需要替换的参数
以上就是Mybatis的动态SQL语句的全部内容。
原文出处
https://blog.csdn.net/weixin_43883917/article/details/113797106