u3764469

导航

Mybatis

一、Mybatis 参数处理

Mybatis 所有参数传递底层是 Map 集合

  1. 四种核心参数传递方式

  2. 多个基本类型参数(无封装)

  3. 用法:接口方法直接声明多个基本类型

// Mapper接口
User login(String username, String password);
  1. 取值方式:XML 中用 arg0,arg1...(按顺序从 0 开始)或 param1,param2...(按顺序从 1 开始)

<select id="login" resultType="cn.wolfcode.user.domain.User">
  select * from user where username=#{param1} and password=#{param2}
</select>
  1. 缺点:参数多时,容易混淆

  2. @Param 注解封装

  3. 用法:通过 @Param 注解指定 Map 的 key ,直接关联 XML 中的取值名

// Mapper接口:给参数指定key为username和password
User login(@Param("username") String username, @Param("password") String password);
  1. 取值方法:XML 直接用注解指定的 key (#{username}、#{password})

  2. 底层原理:自动将参数封装为 Map ,key = 注解值,value = 参数值

  3. Map 手动封装

  4. 用法:手动创建 HashMap ,存入参数键值对,接口方法接收 Map 对象

// Mapper接口
User login(Map<String, Object> map);

// 测试代码
@Test
public void login() {
  Map<String, Object> map = new HashMap<>();
  map.put("username", "admin"); // key=username
  map.put("password", "222");   // key=password
  userMapper.login(map);
}
  1. 取值方式:XML 直接用 Map 的 key(与上面一致)

  2. 适用场景:参数无固定实体类(如多条件筛选的零散参数)

  3. JavaBean 封装

  4. 用法:将参数封装为 JavaBean (如 User、Employee),接口方法接收该对象

// Mapper接口
User login(User u);

// 测试代码
@Test
public void login() {
  User u = new User();
  u.setUsername("admin");
  u.setPassword("222");
  userMapper.login(u);
}
  1. 取值方式:XML 直接用 JavaBean 的属性名

  2. 适用场景:参数与实体类字段对应(如新增,修改,多条件查询)

  3. 特殊参数:List/ 数组

  4. 自动封装规则:Mybatis 会自动将其存入 Map ,无需手动处理

  5. List 集合: Map 的key 固定为 list

  6. 数组:Map 的 key 固定 array

  7. 自定义 key :用@Param注解修改 key 值

// 接口:将List的key改为"ids",替代默认的"list"
void batchDelete(@Param("ids") List<Long> ids);
  1. 取值方式:XML 中通过collection="list"(默认)或collection="ids"(自定义)遍历

二、#{} 与 ${} 的核心区别

  1. 核心差异对比

对比维度 #{} ${}
底层处理 预编译 SQL ,自动给值加英文单引号 直接字符串拼接,不加任何符号
SQL 注入风险 无(参数作为占位符) 有(恶意参数可篡改语法)
取值限制 支持所有类型 不支持单独的基本类型(需封装 Bean/Map)
使用场景 普通参数传递 动态字段名/表名(order by、group by)
  1. 实操实例

  2. #{}

<!-- 参数为"admin",最终SQL自动加单引号 -->
select * from user where username=#{username}
<!-- 解析后SQL:select * from user where username='admin' -->
  1. ${}

<!-- 参数为"sal",直接拼接为字段名,不加单引号 -->
select * from user order by ${sortField}
<!-- 解析后SQL:select * from user order by sal -->

注意:${}不能用于用户输入参数(用户名、密码),否则会引发 Sql 注入

三、动态 SQL

动态 SQL 通过标签自动合法地拼接 SQL ,解决“多条件查询、批量操作、动态更新”的语法问题,无需手动拼接字符串

  1. if 标签(条件判断)

  2. 作用:根据参数是否有效(非空、非空字符串),决定是否拼接该 SQL

  3. 语法:test 属性写 OGNL 表达式

<if test="name != null and name != ''">
  and name like concat('%', #{name}, '%') <!-- 模糊查询 -->
</if>
<if test="minSal != null">
  and sal >= #{minSal} <!-- 数值类型无需判断空字符串 -->
</if>
  1. 关键:test 属性中直接用参数名(与传递方式一致),无需加 #{}

  2. where 标签(条件拼接优化)

  3. 问题:当多个 if 标签进行拼接时,可能出现 “where and ...” 的语法错误(第一个条件带 and)

  4. 作用:自动去除条件开头多余的 and/or ,无有效条件时自动忽略 where 字句

<select id="queryBySal" resultType="cn.wolfcode.user.domain.Employee">
  select * from employee
  <where>
    <if test="minSal != null">
        and sal >= #{minSal}</if>
    <if test="maxSal != null">
        and sal &lt;= #{maxSal}</if> <!-- XML中<=转义为&lt;= -->
  </where>
</select>
  1. 当只有一个生效时,会自动去掉 and

  2. set 标签(动态更新)

  3. 问题:动态更新时,可能出现“set name=?, sn=?,” 的语法错误(最后一个字段带逗号)

  4. 作用:自动去除更新字段末尾多余的逗号,无有效字段时不拼接 set 字句

<update id="edit">
  update employee
  <set>
    <if test="name != null and name != ''">name=#{name},</if>
    <if test="sn != null and sn != ''">sn=#{sn},</if>
    <if test="sal != null">sal=#{sal}</if>
  </set>
  where id=#{id}
</update>
  1. 效果:仅更新传入的非空字段,未传入字段保持原样

  2. foreach 标签(批量操作)

  3. 作用:遍历集合/数组,拼接批量 SQL

  4. 核心属性

  5. collection:遍历的集合/数组名(默认 list/array ,若有设置的注解@Param 指定名用指定名)

  6. item:集合元素的别名(遍历过程中,每个元素的临时名称)

  7. separator:元素间的分割符

  8. open:拼接的起始字符串

  9. close:拼接结束字符串

<delete id="batchDelete">
  delete from employee 
  <foreach collection="ids" item="id" open="where id in (" separator="," close=")">
    #{id}
  </foreach>
</delete>
  1. 效果:传入List<Long> ids = Arrays.asList(1L,2L,3L),生成delete from employee where id in (1,2,3),若没有有效值会直接忽略 foreach 标签删除整个表

posted on 2026-01-27 22:47  北海道第一原神高手  阅读(2)  评论(0)    收藏  举报