Mybatis实现if trim(四)
1. 准备
请先完成Mybatis实现增删改查(二)和Mybatis实现条件查询(三)的基本内容
2. 关于多条件查询的疑问
在Mybatis实现条件查询(三)中我们实现了多条件(商品编码、商品名称、商品价格范围)查询商品信息。但是我们现在有了一个新的疑问:在Mybatis实现条件查询(三)中,如果我们只赋值了PartCode查询条件,而没有赋值其他查询条件,那么会发生什么呢?
我们重新修改下main方法(屏蔽了三行代码,如下):
public static void main(String[] args) { QryPartParam qryPartParam = new QryPartParam(); qryPartParam.setPartCode("001-0001"); //qryPartParam.setPartName("TCL"); //qryPartParam.setSalePriceLow(0f); //qryPartParam.setSalePriceHigh(10000f); List<PartInfo> partInfos = selectPartByUser(qryPartParam);
if (partInfos != null) { for (PartInfo partInfo : partInfos) { System.out.println("ID:"+partInfo.getId()+" 商品:["+ partInfo.getPartCode()+"] "+ partInfo.getPartName()+" ,售价:"+ partInfo.getSalePrice()+"元/"+ partInfo.getUnit());
} }
执行,我们会发现打印出来的结果是空的。为什么会查询不到数据呢?我们跟踪一下SQL执行记录会发现最终生成的SQL语句为:
SELECT * FROM tbInfoPart WHERE PartCode='001-0001' AND PartName LIKE '%'+null+'%' AND SalePrice>=null AND SalePrice<=null
为了避免出现这种情况,我们就需要修改PartMapper文件:
<select id="getPartInfoByUser" parameterType="com.mybatis.entity.QryPartParam" resultType="com.mybatis.entity.PartInfo"> SELECT * FROM tbInfoPart WHERE 1=1 <if test="partCode != null">AND PartCode = #{partCode}</if> <if test="partName != null">AND PartName LIKE '%'+#{partName}+'%'</if> <if test="salePriceLow != null">AND SalePrice <![CDATA[>=]]> #{salePriceLow}</if> <if test="salePriceHigh != null">AND SalePrice <![CDATA[<=]]> #{salePriceHigh}</if> </select>
Mybatis中if为判断标签,如果test的内容成立,则标签内容会最终编译为SQL语句。注意test判断内容中的“partCode”、“partName”等来源于parameterType的值,本例来源:com.mybatis.entity.QryPartParam的属性列表。
也可以这样:
<select id="getPartInfoByUser" parameterType="com.mybatis.entity.QryPartParam" resultType="com.mybatis.entity.PartInfo"> SELECT * FROM tbInfoPart <where> <if test="partCode != null">AND PartCode = #{partCode}</if> <if test="partName != null">AND PartName LIKE '%'+#{partName}+'%'</if> <if test="salePriceLow != null">AND SalePrice <![CDATA[>=]]> #{salePriceLow}</if> <if test="salePriceHigh != null">AND SalePrice <![CDATA[<=]]> #{salePriceHigh}</if> </where> </select>
where 元素知道只有在一个以上的if条件有值的情况下才去插入“WHERE”子句。而且,若最后的内容是“AND”或“OR”开头的,where 元素也知道如何将他们去除。
经过本次改动后就可以正常的查询到商品信息了。
3. 关于更新商品信息的疑问
在Mybatis实现增删改查(二)中我们实现了对商品信息的编辑,我们再仔细看一下当时main的方法:
public static void main(String[] args) { PartInfo partInfo; //查询ID=1的商品并赋值给partInfo partInfo = selectPart(1); System.out.println("原商品信息:["+partInfo.getPartCode()+"] "+ partInfo.getPartName()+" ,售价:"+ partInfo.getSalePrice()+"元/"+ partInfo.getUnit()); //调整该商品的各项属性 partInfo.setPartCode("001-0003"); partInfo.setPartName("康佳(KONKA) LED55U60 55英寸 优酷电视梦想版8核优酷视频海量应用"); partInfo.setUnit("台"); partInfo.setSalePrice(2999.00f); //将新商品保存至数据库 updatePart(partInfo); System.out.println("修改商品完成!"); //重新查看并展示ID=1的商品 partInfo = selectPart(1); System.out.println("新商品信息:["+partInfo.getPartCode()+"] "+ partInfo.getPartName()+" ,售价:"+ partInfo.getSalePrice()+"元/"+ partInfo.getUnit()); }
在上面的代码里,我们先查询出ID=1的商品并赋值给partInfo实例,然后针对partInfo进行了修改并保存,然后重新查询ID=1的商品看了看结果确实是我们想要的效果。但是在实际开发中大部分不是这样:当前端页面向我们请求ID=1的商品信息的时候,我们查询出ID=1的商品并赋值给partInfo实例,然后将partInfo序列化为Json串返回给前端,假设前端页面只能编辑“商品编码”、“商品名称”、“单位”,不能修改也不能展示商品的售价,即前端页面中的Form表单就没有绑定SalePrice,那么当用户做完想要的修改点击保存,然后提交给后台的Json再经过我们的反序列化生成的实例partInfo的salePrice属性会为null,这种情况下我们通过Mybatis执行保存后会发生什么呢?
我们重新修改下main方法测试一下:
public static void main(String[] args) { //查看并展示ID=1的商品 PartInfo partInfoOld = selectPart(1); System.out.println("ID:"+partInfoOld.getID()+" 原商品信息:["+ partInfoOld.getPartCode()+"] "+ partInfoOld.getPartName()+",售价:"+ partInfoOld.getSalePrice()+"元/"+ partInfoOld.getUnit()); //模拟前端返回来Json后我们反序列化的实例,注意没有为salePrice赋值 PartInfo partInfo = new PartInfo(); partInfo.setID(1); partInfo.setPartCode("001-0003"); partInfo.setPartName("康佳(KONKA) LED55U60 55英寸 优酷电视梦想版8核优酷视频海量应用"); partInfo.setUnit("台"); //将商品保存至数据库 updatePart(partInfo); System.out.println("修改商品完成!"); //重新查看并展示ID=1的商品 PartInfo partInfoNew = selectPart(1); System.out.println("ID:"+partInfoNew.getID()+" 新商品信息:["+ partInfoNew.getPartCode()+"] "+ partInfoNew.getPartName()+" ,售价:"+ partInfoNew.getSalePrice()+"元/"+ partInfoNew.getUnit()); }
执行main方法后的打印结果为:
ID:1 新商品信息:[001-0003] 康佳(KONKA) LED55U60 55英寸 优酷电视梦想版8核优酷视频海量应用,售价:1099.90元/台 修改商品完成! ID:1 新商品信息:[001-0003] 康佳(KONKA) LED55U60 55英寸 优酷电视梦想版8核优酷视频海量应用,售价:null元/台
我们发现商品的SalePrice被更新成了null,然后我们跟踪Mybaits编译出来的SQL脚本为:
UPDATE tbInfoPart SET PartCode='001-0003', PartName='康佳(KONKA) LED55U60 55英寸 优酷电视梦想版8核优酷视频海量应用', Unit='台', SalePrice=null WHERE ID=1
为了避免为null的属性被更新到数据库里面我们可以如下调整PartMapper:
<!-- #{} 大括号里面的参数名是和com.mybatis.entity.PartInfo中的属性名对应的 --> <!-- mybatis会自动将其属性值按照数据类型填充到被预编译的SQL脚本中 --> <update id="updatePartInfo" parameterType="com.mybatis.entity.PartInfo"> UPDATE tbInfoPart SET <if test="partCode != null">PartCode=#{partCode},</if> <if test="partName != null">PartName=#{partName},</if> <if test="unit != null">Unit=#{unit},</if> <if test="salePrice != null">SalePrice=#{salePrice}</if> WHERE ID=#{id} </update>
但是这样依然会报错,因为这种情况最终生成的SQL为:
UPDATE tbInfoPart SET PartCode='001-0003', PartName='康佳(KONKA) LED55U60 55英寸 优酷电视梦想版8核优酷视频海量应用', Unit='台', WHERE ID=1
最终生成的SQL在WHERE之前多了一个逗号。为了避免这种情况,我们可以使用Mybatis的trim标签。最终的PartMapper修改结果如下:
<!-- #{} 大括号里面的参数名是和com.mybatis.entity.PartInfo中的属性名对应的 --> <!-- mybatis会自动将其属性值按照数据类型填充到被预编译的SQL脚本中 --> <update id="updatePartInfo" parameterType="com.mybatis.entity.PartInfo"> UPDATE tbInfoPart SET <trim prefix="" suffix="" prefixOverrides="" suffixOverrides=","> <if test="partCode != null">PartCode=#{partCode},</if> <if test="partName != null">PartName=#{partName},</if> <if test="unit != null">Unit=#{unit},</if> <if test="salePrice != null">SalePrice=#{salePrice},</if> </trim> WHERE ID=#{id} </update>
trim标签的属性
1.prefix:前缀覆盖并增加其内容
2.suffix:后缀覆盖并增加其内容
3.prefixOverrides:前缀判断的条件
4.suffixOverrides:后缀判断的条件
即trim标签中编译出的SQL字符串,如果是以prefixOverrides设定的值开头,则会被替换成prefix设定的值。如果是以suffixOverrides设定的值结尾则会被替换成suffix设定的值。
也可以这样:
<!-- #{} 大括号里面的参数名是和com.mybatis.entity.PartInfo中的属性名对应的 --> <!-- mybatis会自动将其属性值按照数据类型填充到被预编译的SQL脚本中 --> <update id="updatePartInfo" parameterType="com.mybatis.entity.PartInfo"> UPDATE tbInfoPart <set> <if test="partCode != null">PartCode=#{partCode},</if> <if test="partName != null">PartName=#{partName},</if> <if test="unit != null">Unit=#{unit},</if> <if test="salePrice != null">SalePrice=#{salePrice},</if> </set> WHERE ID=#{id} </update>
set 元素会动态前置 SET 关键字,同时也会消除无关的逗号,因为用了条件语句之后很可能就会在生成的赋值语句的后面留下这些逗号。
这样我们就可以灵活的更改商品的任意属性而不用顾忌其他属性是否为null了。
4. 目录结构