笔者前几篇文章所记录的mybatis的sql基本都是属于静态的,也就是说一旦实现了,这条sql的功能就是单一的,不能随着参数的变化而动态地发生改变,而动态sql弥补这个缺憾。
笔者认为,静态sql的优势主要是比动态sql略快,因为动态sql需要一定的时间进行判断,特别是当sql语句复杂的时候,静态sql的优势就更明显,但是利弊总不是如此肤浅的,我们需要考虑到人性中惰性。如果当sql语句过于复杂,使用静态sql你需要多写几条这样复杂的sql才能满足参数变化的需要,故此笔者更偏向于使用动态sql,因为笔者不想重复地干一些机械的无用功。
进入正题。
动态sql主要的元素如下(和jstl是很像的)
1.if标签元素
if是最常使用的判断语句,它和test属性是分不开的,因为test就是用于测试条件是否成立的。
<select id="dynamicQueryEmp" parameterType="Emp" resultMap="empResultMap">
SELECT e.* FROM
emp e
<where>
<if test="mgr != null">
and e.mgr=#{mgr}
</if>
<if test="empName != null and empName != ''">
and e.ename like '%${empName}%'
</if>
</where>
</select>
接下来我们做一个需求:如果传入的雇员姓名不为空(null and ''),那么就按照雇员型名进行查找;否则就查询所有雇员。
<select id="queryEmpByName" parameterType="Emp" resultType="Emp" resultMap="empResultMap">
SELECT e.* FROM
emp e
WHERE 1=1
<if test="empName != null and empName != ''">
AND e.ename like '%${empName}%'
</if>
</select><!--1=1是一个很经典的sql注入问题-->
开放接口时需要注意,返回的对象应该使用list装入:
public List<Emp> queryEmpByName(Emp tar);
2.choose,when和otherwise标签元素
前面我说过动态sql和jstl真的很像,从这就可以感受得到。这三个元素的作用类似于switch…case/default语句
下面我们又来做一个需求:
如果传入的雇员姓名不为空,那么就按照雇员的姓名进行模糊查询;如果雇员的姓名为空,那么默认是查找薪水在2000.00到5000.00之间的所有雇员。
<select id="queryEmpByNameOrSalary" parameterType="Emp" resultType="Emp" resultMap="empResultMap">
SELECT e.* FROM
emp e
WHERE 1=1
<choose>
<when test="empName != null and empName != ''">
AND e.ename like '%${empName}%'
</when>
<otherwise>
AND e.salary between 2000.00 and 5000.00
</otherwise>
</choose>
</select><!--1=1是一个很经典的sql注入问题-->
接口开放和上面的要求一样。
3.trim,where和set标签元素
有时候,我们需要去掉一些特殊的sql语法,比如and、or之类的,知识后就需要用到trim标签。通俗地说,通过trim标签我们可以去除sql中的某些字符串,我们改造一下前面的示例。
<select id="queryEmpByName" parameterType="Emp" resultType="Emp" resultMap="empResultMap">
SELECT e.* FROM
emp e
<trim prefix="where" prefixOverride="and">
<if test="empName != null and empName != ''">
AND e.ename like '%${empName}%'
</if>
</trim>
</select><!--1=1是一个很经典的sql注入问题-->
在这里prefix是
AND e.ename like ‘%${empName}%’
成立时填补的前缀,prefixOverride是其成立时去掉前面的and
where标签元素
它的作用是就是判断内部的子句是否成立,若果成立就添上作用相当于where 1=1的sql语句;否则则不添。
<select id="queryEmpByName" parameterType="Emp" resultMap="empResultMap">
SELECT e.* FROM
emp e
<where>
<if test="empName != null and empName != ''">
AND e.ename like '%${empName}%'
</if>
</where>
</select><!--1=1是一个很经典的sql注入问题-->
如果不使用where标签,那么下面这句sql就会无法通过
SELECT e.* FROM
emp e
WHERE
AND e.ename like '%${empName}%'
set标签元素
其主要是复用一段sql,譬如:在一个update的更新中,由于参数的不同可能我们会写多条update sql,对于同一条记录来说,可以一次更新完毕的操作需要分多次来做,这就会显得冗余和性能的耗费。
<update id="updateEmp" parameterType="Emp">
UPDATE
emp e
<set>
<if test="empName != null and empName != ''">
e.emp_name=#{empName},
</if>
<if test="salary != null">
e.salary=#{salary}
</if>
</set>
WHERE
e.emp_no=#{empNo}
</update>
4.foreach标签元素
其主要是用在in关键字中,in是集合中是属于范围内的意思
<select id="queryEmpByName" resultMap="empResultMap">
SELECT e.* FROM
emp e
WHERE
e.salary
IN
<foreach item="s" index="i" collection="salaryList" open="(" separator="," close=")">
#{s}
<foreach>
</select><!--1=1是一个很经典的sql注入问题-->
现在来解释下这段sql,collection属性传入的应该是一个list或array,这里是通过@Param注解传入参数的;
item属性是当前用于遍历salaryList,其实就是和Java中的foreach(增强for循环)一致,多说一句,以后Java往多核编程的方向发展,lambda表达式或者说是函数式编程是必然的。
index属性是当前遍历的下标位置。
open和close属性是配置使用声明符号把里面的元素包装起来。
separator属性是决定使用什么分隔符把元素之间分隔开来。
5.bind标签元素
由于不同的数据库厂商提供的字符串连接的方式是不同的,这样使用mybatis时就必须写不同的sql来适应不同的数据库,mybatis为了解决这个问题,设计了bind语言,其作用就是通过ognl表达式定义了一个变量在上下文中,然后利用这个变量来实现字符串的拼接
<select id="queryEmpByName" parameterType="Emp" resultMap="empResultMap">
<bind name="str" value="'%'+ empName + '%'"/>
SELECT e.* FROM
emp e
<where>
<if test="empName != null and empName != ''">
AND e.ename like #{str}
</if>
</where>
</select>
name属性定义这个变量的名称,value属性拼接字符。
至此,mybatis的基本操作已经记录完毕,接下来的将是深入mybatis的原理了。
转载请注明出处,谢谢!
感谢杨开振先生所著的《深入浅出Mybatis技术原理与实战》,笔者博客的内容一部分是自己实战中的经验,另一部分是学习这本书籍内容的总结。