MyBatis动态语法标签速查
MyBatis速查
<?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.xy.tms.tran.dao.TranSeaPlanMapper"><!--1. BaseResultMap: 这是 ExtListBaseResultMap 继承的基础映射。它应该包含 Base_Column_List SQL片段中定义的所有字段。--><resultMap id="BaseResultMap" type="com.xy.tms.tran.entity.vo.TranSeaPlanListVo"><id column="tran_main_plan_id" property="tranMainPlanId" jdbcType="BIGINT"/><result column="organization_id" property="organizationId" jdbcType="BIGINT"/><result column="tran_order_id" property="tranOrderId" jdbcType="BIGINT"/><result column="tran_main_plan_no" property="tranMainPlanNo" jdbcType="VARCHAR"/><result column="plan_sort" property="planSort" jdbcType="INTEGER"/><result column="remark" property="remark" jdbcType="VARCHAR"/><result column="version" property="version" jdbcType="INTEGER"/><!-- 创建和更新信息通常放在扩展Map中,但为了完整性,这里也可以包含 --><result column="create_by" jdbcType="VARCHAR" property="createBy"/><result column="create_by_name" jdbcType="VARCHAR" property="createByName"/><result column="create_time" jdbcType="TIMESTAMP" property="createTime"/><result column="update_by" jdbcType="VARCHAR" property="updateBy"/><result column="update_by_name" jdbcType="VARCHAR" property="updateByName"/><result column="update_time" jdbcType="TIMESTAMP" property="updateTime"/></resultMap><!--2. ExtListBaseResultMap: 扩展映射。- 继承了 BaseResultMap 的所有映射。- <collection> 标签用于映射一对多关系(一个计划可以有多个角色)。--><resultMap id="ExtListBaseResultMap" type="com.xy.tms.tran.entity.vo.TranSeaPlanListVo"extends="BaseResultMap"><!-- BaseResultMap 中的字段被继承 --><result column="sea_plan_detail_id" jdbcType="BIGINT" property="seaPlanDetailId"/><result column="ship_company_order_no" jdbcType="VARCHAR" property="shipCompanyOrderNo"/><result column="materiel_code" jdbcType="VARCHAR" property="materielCode"/><result column="materiel_name" jdbcType="VARCHAR" property="materielName"/><result column="materiel_id" jdbcType="BIGINT" property="materielId"/><result column="status" jdbcType="VARCHAR" property="status"/><!--角色集合。它使用 `roleResultMap` 来定义如何映射每个角色。要使其工作,查询必须返回一个 `role_name` 列。--><collection property="sysRoleIdList" javaType="java.util.ArrayList" ofType="java.lang.String"resultMap="roleResultMap"/></resultMap><!--3. resultMap,用于映射一个字符串集合。--><resultMap id="roleResultMap" type="java.lang.String"><result column="role_name"/></resultMap><!--4. SQL 片段,用于可重用的列清单。- 使用表别名(如 tsp)是最佳实践,可以避免 JOIN 查询中的列名歧义。--><sql id="Base_Column_List">tsp.tran_main_plan_id, tsp.organization_id, tsp.tran_order_id, tsp.tran_main_plan_no, tsp.plan_sort,tsp.tran_type, tsp.tran_type_desc, tsp.tran_method, tsp.tran_method_desc, tsp.start_station_id, tsp.end_station_id,tsp.audit_status, tsp.audit_status_desc, tsp.audit_time, tsp.audit_user, tsp.allot_status, tsp.allot_status_desc,tsp.delivery_status, tsp.delivery_status_desc, tsp.remark, tsp.create_by, tsp.create_by_name, tsp.create_time,tsp.update_by, tsp.update_by_name, tsp.update_time, tsp.version</gsql><!--5. 包含所有动态部分和修正后逻辑的主查询语句。--><select id="querySeaPlan" parameterType="com.xy.tms.tran.entity.vo.TranSeaPlanQueryVo"resultMap="ExtListBaseResultMap">SELECT<include refid="Base_Column_List"/>,tsp.sea_plan_id,tsp.status,tsp.status_desc,tsp.sea_plan_no,tsp.ship_company_order_no,tsp.book_space_success_flag_desc,tsp.plan_date,tspd.sea_plan_detail_id,tspd.materiel_id,tspd.materiel_code,tspd.materiel_name,-- 为了填充 collection,需要 JOIN 角色表并查询出 role_name-- 注意:如果一个用户有多个角色,这会导致主计划行重复。Mybatis的<collection>会自动处理分组。sr.role_name,CONCAT(IFNULL(mm.materiel_spec,''), IFNULL(mm.packing_weight_unit_desc,''),'/',IFNULL(mm.packing_pieces_unit_desc,'')) as packing_spec_full_desc,pg.product_grade_name,mm.base_unit_desc,tspd.product_grade_idFROM tran_sea_plan tspLEFT JOIN tran_sea_plan_detail tspd ON tsp.sea_plan_id = tspd.sea_plan_id<!-- 根据查询的列,添加了缺失的 JOIN -->LEFT JOIN mst_materiel mm ON tspd.materiel_id = mm.materiel_idLEFT JOIN product_grade pg ON tspd.product_grade_id = pg.product_grade_idLEFT JOIN mst_carrier mc ON tsp.ship_company_id = mc.carrier_id<!-- 添加 JOIN 以获取 role_name 用于 collection -->LEFT JOIN sys_user_role sur ON tsp.create_by = sur.user_idLEFT JOIN sys_role sr ON sur.role_id = sr.role_id<!--<where> 标签会智能地添加 WHERE 关键字(仅当内部有条件时)。它还会自动去除条件前面多余的 "AND" 或 "OR"。--><where><!-- <if> 标签:仅当测试条件为真时,才包含此SQL片段。 --><if test="queryVo.seaPlanNo != null and queryVo.seaPlanNo != ''">AND tsp.sea_plan_no LIKE CONCAT('%', #{queryVo.seaPlanNo}, '%')</if><if test="queryVo.organizationId != null and queryVo.organizationId != ''">AND tsp.organization_id = #{queryVo.organizationId}</if><!--用于处理时间范围查询。<![CDATA[ ... ]]> 用于避免XML解析器将 < 和 > 视为标签。--><if test="startTime != null">AND tsp.create_time <![CDATA[>=]]> #{startTime}</if><if test="endTime != null">AND tsp.create_time <![CDATA[<=]]> #{endTime}</if><!-- <foreach> 标签:遍历一个集合(如List),常用于构建 IN 子句。 --><if test="queryVo.status != null and queryVo.status.size() > 0">AND tsp.status IN<foreach collection="queryVo.status" item="item" open="(" separator="," close=")">#{item}</foreach></if><!-- <choose>, <when>, <otherwise>: 类似于Java的 switch-case 语句,只执行第一个匹配的块。 --><choose><when test="isUpdate != null">AND tsp.update_time = #{isUpdate, jdbcType=TIMESTAMP}</when><when test="isDelete != null"><!-- 假设有一个 is_deleted 字段 -->AND tsp.is_deleted = #{isDelete, jdbcType=INTEGER}</when><otherwise><!-- 默认只查询未删除的记录 -->AND tsp.is_deleted = 0</otherwise></choose><!--<bind> 标签:创建一个可在OGNL表达式中使用的变量。--><if test="userName != null and userName != ''"><bind name="userNameLike" value="'%' + userName + '%'"/>AND tsp.create_by_name LIKE #{userNameLike}</if></where>ORDER BYtsp.create_time DESC, tsp.sea_plan_no DESC</select><!--6. 使用 <set> 的动态 UPDATE--><update id="updateAuthorIfNecessary_withSet">UPDATE Author<set><if test="username != null">username=#{username},</if><if test="password != null">password=#{password},</if><if test="email != null">email=#{email},</if><if test="bio != null">bio=#{bio},</if></set>WHERE id=#{id}</update><!--7. 使用 <trim> 的动态 UPDATE (功能更强,推荐)效果与 <set> 相同,但更灵活。这里它添加 "SET" 前缀,并删除结尾多余的逗号 ","。--><update id="updateAuthorIfNecessary_withTrim">UPDATE Author<trim prefix="SET" suffixOverrides=","><if test="username != null">username=#{username},</if><if test="password != null">password=#{password},</if><if test="email != null">email=#{email},</if><if test="bio != null">bio=#{bio},</if></trim>WHERE id=#{id}</update></mapper>
Mybatis 动态 SQL 标签详解
以下是上述示例中使用的所有动态 SQL 标签的中文解释。
1、<if>
用途: 进行条件判断。如果 test 属性中的表达式值为 true,则会包含 标签内的 SQL。这是最常用的动态标签。
示例: AND tsp.sea_plan_no LIKE …
解释: 只有当 queryVo 对象的 seaPlanNo 属性不为 null 且不为空字符串时,才会将 AND tsp.sea_plan_no LIKE … 这段SQL拼接到最终的语句中。
2、<choose>, <when>, <otherwise>
用途: 实现 “if-else if-else” 的逻辑分支。Mybatis 会选择第一个满足条件的标签,如果所有都不满足,则会选择 标签。
示例: 检查 isUpdate 和 isDelete 标志的那个代码块。
3、<where>
用途: 一个智能的 WHERE 子句包装器。它只在内部有内容生成时才插入 WHERE 关键字。更重要的是,它会自动移除内容开头多余的 AND 或 OR,这让 标签的书写变得非常方便,你可以在每个 条件前都加上 AND,而不用担心第一个条件会出错。
示例: <if …> AND … <if …> AND … 会被正确地解析为 WHERE … AND …。
4、<foreach>
collection: 需要迭代的集合参数。
item: 迭代过程中当前元素的变量名。
open: 在整个循环内容前面添加的字符串(例如 ()。
close: 在整个循环内容后面添加的字符串(例如 ))。
separator: 在每次迭代之间添加的分隔符(例如 ,)。
用途: 用于遍历一个集合(如 List, Set, Array 或 Map),通常用于构建 IN 子句。
属性:
示例: 用于构建 AND tsp.status IN (?, ?, …) 子句。
5、<set>
用途: 用于 UPDATE 语句中。它会智能地插入 SET 关键字,并且会自动删除最后一个字段后面多余的逗号。
示例: updateAuthorIfNecessary_withSet 更新语句。
6、<trim>
用途: 一个非常灵活的标签,用于格式化 SQL。可以添加前缀/后缀,也可以移除指定的前缀/后缀。
作为 的替代方案 (示例中用法): … ,表示在内容前加上 SET,并从内容结尾移除多余的 ,。
作为 的替代方案: … 。
7、<bind>
用途: 在当前 OGNL 上下文中创建一个变量。这常用于在 SQL 中使用该变量之前,对其进行预处理,例如为 LIKE 查询拼接 % 通配符。
示例: 创建了一个名为 userNameLike 的变量,其值为 ‘%某个用户名%’,之后就可以在 SQL 中通过 #{userNameLike} 来引用它。
8、<sql> 和 <include>
用途: 用于定义可重用的 SQL 片段, 用于在其他地方引用这些片段。这对于避免代码重复(特别是长列名列表)非常有用。
示例: … 定义了列清单,而 将其插入到 SELECT 语句中。