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);
    for (PartInfo partInfo : partInfos) {
        System.out.println("ID:"+partInfo.getId()+" 商品:["+
                            partInfo.getPartCode()+"] "+
                            partInfo.getPartName()+" ,售价:"+
                            partInfo.getSalePrice()+"元/"+
                            partInfo.getUnit());
}

执行,我们会发现打印出来的结果是空的。为什么会查询不到数据呢?我们跟踪一下SQL执行记录会发现最终生成的SQL语句为:

SELECT * FROM tbInfoPart WHEE 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) {
    //模拟前端返回来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 = selectPart(1);
    System.out.println("ID:"+partInfo.getID()+" 新商品信息:["+                       partInfo.getPartCode()+"] "+                        partInfo.getPartName()+" ,售价:"+                        partInfo.getSalePrice()+"元/"+                        partInfo.getUnit()); }

执行main方法后的打印结果为:

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. 目录结构

时间: 2024-08-24 14:03:48

Mybatis实现if trim(四)的相关文章

Java Persistence with MyBatis 3(中文版) 第四章 使用注解配置SQL映射器

在上一章,我们看到了我们是怎样在映射器Mapper XML配置文件中配置映射语句的.MyBatis也支持使用注解来配置映射语句.当我们使用基于注解的映射器接口时,我们不再需要在XML配置文件中配置了.如果你愿意,你也可以同时使用基于XML和基于注解的映射语句. 本章将涵盖以下话题: l 在映射器Mapper接口上使用注解 l 映射语句 @Insert,@Update,@Delete,@SeelctStatements l 结果映射 一对一映射 一对多映射 l 动态SQL @SelectProvi

Springboot &amp; Mybatis 构建restful 服务四

Springboot & Mybatis 构建restful 服务四 1 前置条件 成功执行完Springboot & Mybatis 构建restful 服务三 2 restful service 添加 Apache POI生成 Excel 文件 1)修改 POM.xml文件 添加 Apache POI 的依赖 <dependency> <groupId>org.apache.poi</groupId> <artifactId>poi-oo

Mybatis 实用篇(四)返回值类型

Mybatis 实用篇(四)返回值类型 一.返回 List.Map List<User> getUsers(); <select id="getUsers" resultType="User"> select * from user; </select> Map<String, Object> getUsers(); <select id="getUsers" resultType="

mybatis源码分析(四) mybatis与spring事务管理分析

mybatis源码分析(四) mybatis与spring事务管理分析 一丶从jdbc的角度理解什么是事务 从mysql获取一个连接之后, 默认是自动提交, 即执行完sql之后, 就会提交事务. 这种事务的范围是一条sql语句. 将该连接设置非自动提交, 可以执行多条sql语句, 然后由程序决定是提交事务, 还是回滚事务. 这也是我们常说的事务. Connection connection = dataSource.getConnection(); // connection.setTransa

Mybatis源码解析(四) —— SqlSession是如何实现数据库操作的?

Mybatis源码解析(四) -- SqlSession是如何实现数据库操作的? ??如果拿一次数据库请求操作做比喻,那么前面3篇文章就是在做请求准备,真正执行操作的是本篇文章要讲述的内容.正如标题一样,本篇文章最最核心的要点就是 SqlSession实现数据库操作的源码解析.但按照惯例,我这边依然列出如下的问题: 1. SqlSession 是如何被创建的? 每次的数据库操作都会创建一个新的SqlSession么?(也许有很多同学会说SqlSession是通过 SqlSessionFactor

MyBatis学习笔记(四)一多一关系

Student中包含Address [html] view plain copy package com.skymr.mybatis.model; public class Student { private int id; private String name; private int age; private Address address; /** * 必须要有无参构造器,有参构造器可有可无(至少我测试时是这样) * 如果没有无参构造器,只有有参构造器,会报错 */ public Stu

Mybatis基础入门(四)——与springMVC的集成

前面的增删改查还没有融入到一个web项目中,这里在前面的基础上,集成spring管理相关的bean,并在web层集成springmvc.同样会有源码的下载. 一.目录结构: 二.集成spring: 因为是一个web项目,且使用了spring作为粘合剂,相关的jar包就不多解释了,详见源码.项目上篇文章中的结构,这里把映射文件单独放到一个目录,而且添加了Controller的包,映射文件内容不变.注意到这里讲其他配置文件整合到了config包中.因为使用spring,所以Configuration

Spring和MyBatis配置补充(四)

一.配置properties属性文件读取数据源信息 1.db.properties的配置属性文件 driver=com.mysql.jdbc.Driver url=jdbc:mysql://localhost:3306/test?characterEncoding=utf-8 name=root pass=0000 2.spring核心配置文件的编写 <!-- 使用属性文件配置数据源 --> <bean id="propertyPlaceholderConfigurer&quo

mybatis标签之——&lt;trim&gt;

https://www.cnblogs.com/zjfjava/p/8882614.html trim标记是一个格式化的标记,主要用于拼接sql的条件语句(前缀或后缀的添加或忽略),可以完成set或者是where标记的功能. trim属性主要有以下四个  prefix:前缀覆盖并增加其内容  suffix:后缀覆盖并增加其内容  prefixOverrides:前缀判断的条件  suffixOverrides:后缀判断的条件 例如在update中 <update id="updateByP