动态SQL

为什么需要动态SQL
  • 学习新技术前我们需要知道为什么需要学习这个技术,即这项技术有什么用,在我们的开发过程中有哪些场景可以用到?
  • 我们之前的SQL语句要么是静态的,要么是可以预测的(参数固定的)。但在实际应用中在很多场景下,sql语句并不是固定的。比如:批量删除功能,我们无法预测用户需要删除多少数据,因此我们无法提前编写好sql语句。再比如:用户指定多个属性进行查询,我们也无法确定用户是根据哪些属性进行查询。
  • 以上的业务场景,都不能使用现有的技术来解决,或者说如果使用现有技术会十分麻烦。而动态SQL能够很好的解决该问题。
  • 所谓动态SQL,简单来说就是指SQL语句是动态变化的。能够根据不同的业务场景,得到合适的SQL语句。
if标签
  • 使用场景:多条件查询

  •     <select id="selectByMulti" resultType="car">
            <!--test属性为真则执行标签内的语句-->
            select * from t_car where 1 = 1
            <!--疑问:
                还有为什么核心配置文件中的mappers标签内不用指定Mapper.xml的路径了
                需要再去看一下别名
            -->
            <if test="#{brand} != null and #{brand} != ''">
                and brand like "%"#{brand}"%"
            </if>
            <if test="#{price} != null and #{price} != ''">
                and guide_price >= #{price}
            </if>
            <if test="#{carType} != null and #{carType} != ''">
                and car_type = #{carType}
            </if>
        </select>
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32

    ##### where标签

    * 场景需求:在上面的if条件中,为了避免某些条件不成立导致sql语句格式的错误,我们在语句中添加了where 1 = 1这一段代码,这非常的不美观。

    * 我们可以使用where标签使SQL语句更加智能化。

    * 作用

    * 当条件都不成立时,使用where标签后,不会生成where语句。

    * 能够智能化的删减前面的and或or。比如:当第一个条件成立时,使用了where标签,那么它能够自动化的检测出and关键字是多余的,并且会将其删除。

    * 这里需要注意的是:where标签只能检测出是否多余了and或or关键字并将多余的删除,并不能检测出是否缺失了and或or关键字,自然不会填补上缺失的关键字。还有,where标签只能检测and在前面的语句,对and在后面的语句无效。比如guide_price >= #{price} and.

    * **所以建议在使用where标签使SQL语句更加智能化时,在每个条件中都写上and关键字,且写在前面**

    * ```xml
    <select id="selectByMultiWithWhere" resultType="car">
    select * from t_car
    <where>
    <if test="#{brand} != null and #{brand} != ''">
    and brand like "%"#{brand}"%"
    </if>
    <if test="#{price} != null and #{price} != ''">
    and guide_price >= #{price}
    </if>
    <if test="#{carType} != null and #{carType} != ''">
    and car_type = #{carType}
    </if>
    </where>
    </select>
    *
trim标签
  • trim标签也能解决以上问题

  • 在trim标签中有4个属性

    • prefix:在标签体前加上一个前缀
    • suffix:在标签体后加上一个后缀
    • prefixoverride:删除sql语句的前缀
    • suffixoverride:删除sql语句的后缀,对where标签不能删除and出现在语句后面的情况做出了补充。比where标签功能更加强大
  •     <select id="selectByMultiWithTrim" resultType="car">
            select * from t_car
            <trim prefix="where" prefixOverrides="and|or">
                <if test="#{brand} != null and #{brand} != ''">
                    and brand like "%"#{brand}"%"
                </if>
                <if test="#{price} != null and #{price} != ''">
                    and guide_price >= #{price}
                </if>
                <if test="#{carType} != null and #{carType} != ''">
                    and car_type = #{carType}
                </if>
            </trim>
        </select>
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27

    ##### set标签

    * 需求场景:我们在进行数据库表的更新时,有可能只需要修改某一个字段,对于其他字段我们提交的数据都是null。如果采用原始做法,那么会将其他数据都更新为null,这肯定不是我们想要看到的。

    * set标签能够解决以上问题,如果提交的数据为null,那么使用set标签将不会修改该字段。并且使用set标签还能够去除多余的逗号。

    * ```xml
    update t_car
    <set>
    <if test="carNum != null and carNum != ''">
    car_num = #{carNum},
    </if>
    <if test="brand != null and brand != ''">
    brand = #{brand},
    </if>
    <if test="guidePrice != null and guidePrice != ''">
    guide_price = #{guidePrice},
    </if>
    <if test="produceTime != null and produceTime != ''">
    produce_time = #{produceTime},
    </if>
    <if test="carType != null and carType != ''">
    car_type = #{carType},
    </if>
    </set>
    where id = #{id}
choose-when-otherwise标签
  • 就是java中的嵌套条件语句:if-else if-else

  •   select * from t_car
            <where>
                <choose>
                    <when test="brand != null and brand != ''">
                        brand = #{brand}
                    </when>
                    <when test="price != null and price != ''">
                        guide_price >= #{price}
                    </when>
                    <otherwise>
                        car_type = #{carType}
                    </otherwise>
                </choose>
            </where>
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27

    ##### foreach标签

    * 就是循环

    * 批量删除

    * ```xml
    <delete id="deleteByIds">
    delete from t_car where id in
    <!--
    collection:需要进行遍历的集合或数组对象 item:当前枚举的元素
    separator:元素与元素之间以什么分隔
    open:循环体以什么开始
    close:循环体以什么结束
    -->
    <foreach collection="ids" item="a" separator="," open="(" close=")">
    #{a}
    </foreach>
    <!--
    另一种批量删除的方法
    delete from t_car where
    <foreach collection = "ids" item = "a" sparator="or">
    id = #{a}
    </foreach>
    -->
    </delete>
Sql与include标签
  • sql标签:将某个代码片段声明为sql语句

  • include标签:使用sql片段

  • 可以提高代码复用性,使代码更容易维护

  •  <sql id="carColumeSql">
            id,car_num as carNum,brand,guide_price as guidePrice,
            produce_time as produceTime,car_type as carType
        </sql>
        <select id="selectById" resultType="com.deng.mybatis.pojo.Car">
            select
            <include refid="carColumeSql"></include>
            from t_car where id = #{id};
        </select>