动态SQL
mybatis在为我们书写SQL语句的时候提供了很大的方便,它允许我们通过一系列标签灵活的操控我们的SQL语句。下面介绍这些标签以及它们的使用方法
相关标签的介绍
- if
- choose
- when
- otherwise
- where
- trim
- set
- foreach
- bind
- sql
下面介绍每个标签的使用方法
if
顾名思义,if标签用于判断条件的正确与否,如果正确会执行if标签体里面的SQL语句,如果条件不成立,则不会执行
if标签属性介绍
- test:用于存放判断条件,这与JSTL表达式很相似,但是里面用的却是OGNL表达式,而非EL表达式
例:
<select id="getEmpsByConditionIf" resultType="com.jinxin.bean.Employee"> SELECT * FROM tb1_employee WHERE <!-- test:判断表达式,与JSTL不同,这里面的不是el表达式而是OGNL表达式 OGNL表达式中的值是从传来的参数中获取的 --> <if test="id!=null"> id=#{id} </if> <if test="lastName!=null and lastName!=''"> AND last_name LIKE #{lastName} </if> <if test="email!=null and email.trim()!=''"> AND email=#{email} </if> <if test="gender==0 or gender==1"> AND gender=#{gender} </if> </select>
where
上面使用if标签先进行条件判断。例如,如果传来的id不为空,则会执行 id = #{id} 的操作,否则不会执行,其他的项亦然,但是这有一个问题,如果第一个id的判断不成立,那么就不会显示 id = #{id} ,那么整个SQL最终必然是 WHERE 后面直接就跟了 AND,所以会出错
那么如何解决这个问题呢?有两种方式
1、既然错误的根源是因为第一个判断不成立而使得后面的SQL会多出一个AND,那么干脆在所有的判断之前加一个绝对成立的判断,例如 1 = 1 ,这样在后面所有的判断中的SQL之前都带上 AND即可。但是这种方式未免太不优雅了,放弃
2、既然上面的方法因为不够优雅而受诟病,那么有没有更为优雅的解决方案呢?于是便有了where标签,where标签能够将前面多余SQL自动去掉
例:
<select id="getEmpsByConditionIf" resultType="com.jinxin.bean.Employee"> SELECT * FROM tb1_employee <where> <if test="id!=null"> id=#{id} </if> <if test="lastName!=null and lastName!=''"> AND last_name LIKE #{lastName} </if> <if test="email!=null and email.trim()!=''"> AND email=#{email} </if> <if test="gender==0 or gender==1"> AND gender=#{gender} </if> </where> </select>
trim
上面的where元素虽然能够解决SQL前面多余AND的问题,但是如果后面有多余的AND或者其他的字符怎么办?此时where无能为力,但是不要慌,还有一个更加好用的标签——trim,trim不但能够去掉它所包含的SQL前面多余的字符,还能去掉其后面多余的字符,不但如此,它还能在前后加上想要的字符,那么看看怎样使用吧
trim标签属性介绍:
- prefix:前缀,给trim包含的SQL前面加上一个前缀
- prefixOverrides:前缀覆盖,去掉前面的指定字符,例如AND 或 OR
- suffix:后缀,给trim包含的SQL加一个后缀
- suffixOverrides:后缀覆盖,去掉后面指定的字符,例如逗号,AND、OR什么的
例:
<select id="getEmpsByConditionIf" resultType="com.jinxin.bean.Employee"> SELECT * FROM tb1_employee <trim prefix="WHERE" suffixOverrides="AND | OR"> <if test="id!=null"> id=#{id} </if> <if test="lastName!=null and lastName!=''"> AND last_name LIKE #{lastName} </if> <if test="email!=null and email.trim()!=''"> AND email=#{email} </if> <if test="gender==0 or gender==1"> AND gender=#{gender} </if> </trim> </select>
choose
choose有类似于switch的效果,但是又有些不同,switch的条件是在switch里面给定的,然后去case里面匹配,这一点跟前面使用resultMap封装结果集的时候使用的discriminator更加相似。而choose的判断却是在每一个when标签里面判断,而且判断的条件不唯一
choose下有两个字标签:一个是when,一个是otherwise
when:
- test:用来放判断条件
otherwise:如果前面所有的when都没有通过,就会执行这里面的sql
例:
<select id="getEmpsByChoose" resultType="com.jinxin.bean.Employee"> SELECT * FROM tb1_employee <where> <!-- 如果带了id据按照id查询,如果带了lastName就按照lastName查询 --> <choose> <when test="id!=null"> id=#{id} </when> <when test="lastName!=null"> last_name LIKE #{lastName} </when> <when test="email!=null"> email=#{email} </when> <otherwise> 1=1 </otherwise> </choose> </where> </select>
set
同where一样,set是用于封装修改条件的(where用于封装查询条件)
where是为了解决and多余的问题,同样set是为了解决更新过程中逗号多余的问题
例:
<update id="updateEmp"> UPDATE tb1_employee <set> <if test="last_name!=null"> last_name=#{lastName}, </if> <if test="email!=null"> email=#{email}, </if> <if test="gender!=null"> gender=#{gender} </if> </set> WHERE id=#{id} </update>
foreach
foreach,见名知意,是用来做循环的,对于传来的参数是集合或者数组的情况下,就可以使用foreach处理。
如下,想要筛选出id属于某个集合的数据
mapper:mapper里面的方法会传入一个参数,这个参数是一个List,里面保存了一个id的集合
List<Employee> getEmpByForeach(List<Integer> ids);
然后就可以通过foreach拼装条件,首先对foreach的属性进行介绍
- collection:指定要遍历的集合,在前面mapper映射文件那篇博客中有提到过,list类型的参数会被封装在map里面,使用list或者collection取出即可
- item:代表当前循环的元素
- separator:指定每个元素中间的分割符,也就是循环之间的分割符
- open:开始拼装前要加的字符,相当于加一个前缀
- close:结束拼装前要加的字符,相当于加一个后缀
- index:索引,在遍历List的时候就是索引值,在遍历map的时候就是map的key,value在上面提到的item里面
例:
<select id="getEmpByForeach" resultType="com.jinxin.bean.Employee"> SELECT * FROM tb1_employee WHERE id IN <!-- collection: 指定要遍历的集合,list类型的参数会做特殊处理封装在map中,map的key就叫做list item:当前遍历的元素 separator:指定每个元素之间的分割符 open:拼装结果开始的字符 close:拼装结果结束的字符 index:索引,遍历List的时候就是索引值,遍历map的时候index表示的就是map的key,item表示的是值 #{变量名} 就能取出当前遍历的元素 --> <foreach collection="list" item="item_id" separator="," open="(" close=")"> #{item_id} </foreach> </select>
foreach批量插入
上面介绍了foreach基本的用法,那么使用foreach还能做什么呢?有一个需求特别适合用foreach实现。
现在有一个集合,里面保存的是元素是某张表的实体类,现在有很多数据,我们希望一次性批量插入
首先应该明确,使用SQL应该怎样做批量插入?如下:
INSERT INTO tb1_employee(last_name, email, gender, d_id)
VALUES ("tina", "tina@163.com", '0', 1), ("frank", "frank@163.com", '1', 2)
可见,上面是通过在VALUES后面以一个扩招为一个单位进行批量插入的
那么已经非常明确了,我们需要做的就是使用foreach去循环后面的这几个括号进行批量插入
<insert id="addEmps"> INSERT INTO tb1_employee(last_name, email, gender, d_id) VALUES <foreach collection="emps" item="emp" separator=","> (#{emp.lastName}, #{emp.email}, #{emp.gender}, #{emp.department.id}) </foreach> </insert>
其实除了上面在value后面跟上多个插入的数据以外,还有一个想法,能否每条数据直插入一条记录,然后执行多次。但是mysql默认不支持一次执行多个sql语句,如果要一次执行多条语句,需要去url上开启执行多条语句: jdbc:mysql://localhost:3306/mybatis?allowMultiQueries=true
这样后mysql就可以一次执行多条SQL语句了
<insert id="addEmps"> <foreach collection="emps" item="emp" separator=";"> INSERT INTO tb1_employee(last_name, email, gender, d_id) VALUES (#{emp.lastName}, #{emp.email}, #{emp.gender}, #{emp.department.id}) </foreach> </insert>
oracle批量插入
在oracle中是不支持在VALUES跟多条记录进行保存的,那么上面针对mysql的批量保存方法就不适用于oracle了,那么在oracle中应该怎样批量保存呢
1、可以使用PLSQL插入
BEGIN
INSERT INTO tb1_employee(id, last_name, email)
VALUES(employee_seq.nextval, ‘Sam’, ‘Sam@163.com’);
INSERT INTO tb1_employee(id, last_name, email)
VALUES(employee_seq.nextval, ‘Jim’, ‘Jim@163.com’);
END;
2、利用中间表
INSERT INTO tb1_employee(id, last_name, email)
SELECT employee_seq.nextval, lastName, email FROM(
SELECT ‘test’ lastName, ‘test@163.com’ email FROM dual
union
SELECT ‘test1’ lastName, ‘test1@163.com’ email FROM dual
union
SELECT ‘test2’ lastName, ‘test2@163.com’ email FROM dual
)
两个内置参数
除了方法中传递的参数可以被用来判断,取值以外。mybatis还提供了两个内置参数
_parameter
_parameter代表了整个参数
-
单个参数:_parameter就是这个参数
-
多个参数:参数会被封装成一个map,_parameter就是代表这个map
_databaseId
_databaseId:如果在全局配置文件中配置了databaseIdProvider标签。_databaseId就是代表当前数据库的别名(oracle、mysql、Sqlite等)
bind
有时如果我们传来的参数过长,或者通过 属性.属性 的方式链的太长了,而这个变量又大量使用,那么可以使用bind给它取一个别名,方便使用
bind属性说明:
- name:别名
- value:要替换的变量
例:
<select id=”getEmpByLastName” resultType=”Employee”> <bind name=”_lastName” value=”’%’ + lastName + ‘%’” /> SELECT * FROM tb1_employee WHERE last_name LIKE #{_lastName} </select>
sql
使用sql可以抽取可以重用的SQL片段,方便后面引用
例:
<sql id="insertColumn"> employee_id, last_name, email </sql> <select id="addEmp" databaseId="oracle"> <!-- include:引用外部定义的sql --> INSERT INTO tb1_employee(<include refid="insertColumn"> </include>) VALUES ... </select>

浙公网安备 33010602011771号