sqle icon indicating copy to clipboard operation
sqle copied to clipboard

解析Mybatis xml文件互斥if标签有问题

Open stronglxp opened this issue 7 months ago • 2 comments

版本信息(Version)

问题描述(Describe)

含有互斥if时,解析有问题. 原内容如下:

<select id="queryWoBillInfoByBillId" resultType="java.util.Map">
        select
        spb.deal_code as "account",
        swb.contact_phone as "contactPhone",
        (select bpb2 .city_code from baf.baf_pub_bureau bpb2 where bpb2.bureau_id=spb.nativenet_id) as "cityId",
        (select bpb.business_name from baf.baf_pub_business bpb where bpb.business_id = spb.specialty_id) as "proType",
        swb.sub_name as "userName",
        swb.inst_address as "address"
        from
        <if test="isHis == 0">
            pub.svr_pub_bill spb,
            wo.svr_wo_bill swb
        </if>
        <if test="isHis == 1">
            pub.svr_pub_bill_his spb,
            wo.svr_wo_bill_his swb
        </if>
        where
        spb.bill_id = swb.bill_id
        and spb.bill_id = #{billId}
    </select>

解析出来的sql如下

select
        spb.deal_code as "account",
        swb.contact_phone as "contactPhone",
        (select bpb2 .city_code from baf.baf_pub_bureau bpb2 where bpb2.bureau_id=spb.nativenet_id) as "cityId",
        (select bpb.business_name from baf.baf_pub_business bpb where bpb.business_id = spb.specialty_id) as "proType",
        swb.sub_name as "userName",
        swb.inst_address as "address"
        from
        
            pub.svr_pub_bill spb,
            wo.svr_wo_bill swb
        
            pub.svr_pub_bill_his spb,
            wo.svr_wo_bill_his swb
        
        where
        spb.bill_id = swb.bill_id
        and spb.bill_id = ?

截图或日志(Log)

如何复现(To Reproduce)

问题原因

解决方案

变更影响面

受影响的模块或功能

外部引用的潜在问题或风险

版本兼容性

测试建议

stronglxp avatar May 13 '25 03:05 stronglxp

TODO

  • [ ] 修复后在微信群艾特:圣雄肝帝

复现过程

使用下面内容填充的xml文件在快捷审核中能够稳定复现

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.example.mapper.YourMapper">

    <select id="queryWoBillInfoByBillId" resultType="java.util.Map">
        select
        spb.deal_code as "account",
        swb.contact_phone as "contactPhone",
        (select bpb2.city_code from baf.baf_pub_bureau bpb2 where bpb2.bureau_id=spb.nativenet_id) as "cityId",
        (select bpb.business_name from baf.baf_pub_business bpb where bpb.business_id = spb.specialty_id) as "proType",
        swb.sub_name as "userName",
        swb.inst_address as "address"
        from
        <if test="isHis == 0">
            pub.svr_pub_bill spb,
            wo.svr_wo_bill swb
        </if>
        <if test="isHis == 1">
            pub.svr_pub_bill_his spb,
            wo.svr_wo_bill_his swb
        </if>
        where
        spb.bill_id = swb.bill_id
        and spb.bill_id = #{billId}
    </select>

</mapper>

Image

winfredLIN avatar May 13 '25 06:05 winfredLIN

补充

MyBatis 支持的动态 SQL 标签主要用于在 XML 映射文件中根据条件动态生成 SQL 语句。这些标签基于 <script> 标签内编写,常用于 <select><insert><update><delete> 等语句中。

以下是 MyBatis 支持的所有动态 SQL 标签(来自 org.apache.ibatis.scripting.xmltags 包):


✅ 条件判断类标签:

  1. <if>

    • 根据 test 条件判断是否包含某段 SQL。

    • 示例:

      <if test="name != null">
        AND name = #{name}
      </if>
      
  2. <choose>

    • 类似 Java 中的 switch-case。

    • 子标签有 <when><otherwise>

      <choose>
        <when test="status == 'active'">
          AND status = 'ACTIVE'
        </when>
        <when test="status == 'inactive'">
          AND status = 'INACTIVE'
        </when>
        <otherwise>
          AND status = 'UNKNOWN'
        </otherwise>
      </choose>
      

✅ 逻辑组合类标签:

  1. <where>

    • 自动处理 AND / OR 前缀,拼接 SQL 的 WHERE 子句。

      <where>
        <if test="name != null">name = #{name}</if>
        <if test="age != null">AND age = #{age}</if>
      </where>
      
  2. <set>

    • 用于动态拼接 UPDATE 语句中的 SET 子句,自动去除最后一个逗号。

      <set>
        <if test="name != null">name = #{name},</if>
        <if test="age != null">age = #{age},</if>
      </set>
      
  3. <trim>

    • 高级标签,可以定制前缀、后缀、前后缀覆盖等。

    • 常用于代替 <where><set>

      <trim prefix="WHERE" prefixOverrides="AND |OR ">
        <if test="name != null">AND name = #{name}</if>
        <if test="age != null">OR age = #{age}</if>
      </trim>
      

✅ 循环类标签:

  1. <foreach>

    • 用于遍历集合(如 List、Array、Map),生成 IN (...) 语句等。

      <foreach collection="ids" item="id" open="(" separator="," close=")">
        #{id}
      </foreach>
      

✅ 其他标签:

  1. <bind>

    • 用于创建临时变量,可以用于字符串拼接、正则表达式处理等。

      <bind name="pattern" value="'%' + name + '%'" />
      <if test="name != null">AND name LIKE #{pattern}</if>
      

✅ 根标签(MyBatis 3.5+ 推荐):

  1. <script>

    • 顶层包装标签,声明该 SQL 为动态 SQL。

      <select id="findUser" resultType="User">
        <script>
          SELECT * FROM user
          <where>
            <if test="name != null">AND name = #{name}</if>
          </where>
        </script>
      </select>
      

winfredLIN avatar May 13 '25 06:05 winfredLIN