MyBatis(四)——动态SQL
1.概念
静态的SQL语句是写死的,如果很复杂,一不小心写错,就会报错。
动态的SQL语句可以更具需要自行拼接,动态组装的意思,即根据传入参数来拼接SQL语句。
2.条件
静态SQL时,POJO的属性名 在 XxxMapper.xml文件中的#{属性名}默认一一对应。
动态SQL时,不会有默认效果,需要用map封装属性名,或者用@Param注解属性名。其实都是有map封装属性名这个操作步骤。
3.<if>
常规的判断
<!-- Customer selectById(Map<String, Object> map); --> <select id="selectById" resultType="com.atguigu.mybatis.bean.Customer"> select * from customer where 1=1 <if test="id != null"> and id=#{id} </if> </select>
用一个test属性来动态判断,一般在条件前加上1=1这类肯定判断,否则会导致拼接成select * from customer where and id=#{id}这样的错误句子。
4.<choose>-<when>-<otherwise>
有些情况,只需要取一个条件值(多选一)就可以结束的话,如果判断全部的<if>都不太合适,由于没有else if这种效果的标签,就用<choose>-<when>-<otherwise>标签,效果类似Java语言中的switch-case-default语句。这里用注解@Param隐形封装map的属性。修改测试参数值或者<when><otherwise>里条件再进行测试。
<!-- System.out.println(mapper.selectByIdAndNameAndJobs(2, "猴子","射手")); --> <!-- List<Customer> selectByIdAndName(@Param("id")Integer id,@Param("username")String username,@Param("jobs")String jobs); --> <select id="selectByIdAndNameAndJobs" resultType="com.atguigu.mybatis.bean.Customer"> select * from customer where 1=1 <choose> <when test="id==null"> and id=#{id} </when> <when test="username==null"> and username=#{username} </when> <otherwise> and jobs=#{jobs} </otherwise> </choose> </select>
5.<where>
在第3点<if>的代码中,加了where 1=1来拼接后面的and,防止出错。也可以用<where>来实现,他会自动判断组合条件下拼装的SQL语句,即 有多余的[and]或[or]会自动除去。(感觉还是不如where 1=1好用,可能是语句还不够复杂,体现不出效果)
<!-- System.out.println(mapper.selectByIdAndNameAndJobs(2, "猴子","射手")); --> <!-- List<Customer> selectByIdAndName(@Param("id")Integer id,@Param("username")String username,@Param("jobs")String jobs); --> <select id="selectByIdAndNameAndJobs" resultType="com.atguigu.mybatis.bean.Customer"> select * from customer <where> <if test="id!=null"> and id=#{id} </if> <if test="username!=null"> and username=#{username} </if> <if test="jobs!=null"> or jobs=#{jobs} </if> </where> </select>
6.<trim>
<trim>-<if>常用于SQL语句选择性插入或者除去多余的关键字,例如[and]、[,]等
prefix:要拼接的前缀
prefixOverrides:要删除的前缀
suffix:要拼接的后缀
suffixOverrides:要删除的后缀
<!-- System.out.println(mapper.selectByIdAndNameAndJobs(2, "猴子","射手")); --> <!-- List<Customer> selectByIdAndName(@Param("id")Integer id,@Param("username")String username,@Param("jobs")String jobs); --> <select id="selectByIdAndNameAndJobs" resultType="com.atguigu.mybatis.bean.Customer"> select * from customer <trim prefix="where" prefixOverrides="or|and"> <if test="id!=null">and id=#{id}</if> <if test="username!=null and username.length()>0"> and username=#{username} </if> <if test="jobs==null">or jobs=#{jobs}</if> </trim> </select>
这里指的SQL语句是<trim>围起来的语句,不涉及前面写好的,即对<if>里的条件判断后,将<if>标签里的SQL语句拼接起来,然后再去掉[要删除的前缀],加上要[拼接的前缀]。
这里<trim>里判断后形成的句子是[and id=? and username=? or jobs=?]
再去掉前缀[and],变成了[id=? and username=? or jobs=?],
再拼上前缀[where],变成了[where id=? and username=? or jobs=?],
再和<trim>前的SQL语句拼接,变成了[select * from customer where id=? and username=? or jobs]。
后缀同理。
7.<set>
<set>-<if>用于修改语句,他的作用是像<where>一样先拼接一个[set],对于<if>里的自动除去末尾的[,],修改语句常有连接的[,]
<!-- Boolean updateName(Map<String,Object> map); --> <update id="updateName" > update customer <set> <if test="newname!=null"> username=#{newname},</if> <if test="jobs!=null">jobs=#{jobs},</if> </set> where username=#{oldname} </update>
语句:[update customer SET username=?, jobs=? where username=? ]
8.<foreach>
item:循环中的具体对象,在list和数组中是其中的对象,在map中是value。该参数为必选。
index:在list和数组中,index是元素的序号,在map中,index是元素的key,该参数可选。
collection:foreach的对象,作为入参时,List<?>对象默认用list代替作为键,数组对象有array代替作为键,Map对象用map代替作为键。 当然在作为入参时可以使用@Param("keyName")来设置键,设置keyName后,list,array,map将会失效。 除了入参这种情况外,还有一种作为参数对象的某个字段的时候。举个例子: 如果User有属性List ids。入参是User对象,那么这个collection = "ids" 如果User有属性Ids ids;其中Ids是个对象,Ids有个属性List id;入参是User对象,那么collection = "ids.id" 上面只是举例,具体collection等于什么,就看你想对那个元素做循环。 该参数为必选。
open:开始符号,一般是(和close=")"合用。常用在in(),values()时。该参数可选。
separator:元素之间的分隔符,例如在in()的时候,separator=","会自动在元素中间用“,“隔开,避免手动输入逗号导致sql错误,如in(1,2,)这样。该参数可选。
close:关闭符号,一般是)和open="("合用。常用在in(),values()时。该参数可选。
9.<bind>