当前位置: 首页 > news >正文

MyBatis 参数传递详解:从基础到复杂场景全解析

一、参数传递概述:为什么参数处理如此重要?

在 MyBatis 开发中,参数传递是连接 Java 代码与 SQL 语句的桥梁,直接影响 SQL 执行的正确性。不合理的参数传递方式可能导致:

  • SQL 语法错误
  • 参数值无法正确映射
  • 潜在的 SQL 注入风险
  • 代码可读性和可维护性下降

MyBatis 提供了灵活多样的参数传递方式,能应对从简单到复杂的各种业务场景。本文将系统讲解 MyBatis 的参数处理机制,涵盖基本类型、对象、集合等多种参数类型,并通过实例展示最佳实践。

二、单个参数传递:最简单的参数处理方式

当 Mapper 接口方法只有一个参数时,MyBatis 的处理方式最为灵活,无需额外配置即可直接使用。

2.1 基本类型参数

Mapper 接口

java

运行

// 根据ID查询用户
User getUserById(Integer id);

映射文件

xml

<select id="getUserById" resultType="User">SELECT * FROM user WHERE id = #{id}
</select>

说明

  • #{id}中的名称可以任意,如#{xxx}也能正常工作
  • MyBatis 会自动根据参数类型进行类型转换
  • 支持的基本类型包括:intlongStringboolean

2.2 字符串参数与模糊查询

Mapper 接口

java

运行

// 根据用户名模糊查询
List<User> getUserByUsername(String username);

映射文件

xml

<select id="getUserByUsername" resultType="User">SELECT * FROM user WHERE username LIKE CONCAT('%', #{username}, '%')
</select>

注意

  • MySQL 中使用CONCAT()函数拼接通配符
  • Oracle 中可直接使用'%'||#{username}||'%'
  • 避免使用字符串拼接(${username})防止 SQL 注入

2.3 单个对象参数

当参数是一个 Java 对象时,#{}中需要使用对象的属性名:

Mapper 接口

java

运行

// 根据用户对象查询(演示用)
User getUserByUser(User user);

映射文件

xml

<select id="getUserByUser" resultType="User">SELECT * FROM user WHERE username = #{username} AND age = #{age}
</select>

说明

  • #{username}对应 User 对象的getUsername()方法
  • 必须保证对象有对应的 Getter 方法
  • 参数类型可省略(MyBatis 会自动推断)

三、多个参数传递:@Param 注解的正确使用

当方法有多个参数时,MyBatis 无法直接识别参数名称,需要使用@Param注解显式指定。

3.1 多个基本类型参数

Mapper 接口

java

运行

// 多条件查询
List<User> getUserByAgeAndEmail(@Param("minAge") Integer minAge,@Param("maxAge") Integer maxAge,@Param("email") String email
);

映射文件

xml

<select id="getUserByAgeAndEmail" resultType="User">SELECT * FROM user WHERE age BETWEEN #{minAge} AND #{maxAge}AND email LIKE CONCAT('%', #{email}, '%')
</select>

关键点

  • @Param注解中的值必须与#{}中的名称一致
  • 不使用@Param时,MyBatis 会使用arg0arg1param1param2作为参数名
  • 推荐始终使用@Param,提高代码可读性

3.2 混合参数类型

方法参数可以是基本类型、对象、集合等的混合:

Mapper 接口

java

运行

// 混合参数查询
List<User> getMixedParams(@Param("user") User user,@Param("status") Integer status,@Param("roles") List<String> roles
);

映射文件

xml

<select id="getMixedParams" resultType="User">SELECT * FROM user WHERE username = #{user.username}AND status = #{status}AND role IN <foreach collection="roles" item="role" open="(" separator="," close=")">#{role}</foreach>
</select>

说明

  • 引用对象属性时使用#{对象名.属性名}格式
  • 集合参数可配合foreach标签使用

四、特殊参数类型:数组、集合与 Map

4.1 数组参数

Mapper 接口

java

运行

// 根据ID数组查询
List<User> getUserByIds(@Param("ids") Integer[] ids);

映射文件

xml

<select id="getUserByIds" resultType="User">SELECT * FROM user WHERE id IN <foreach collection="ids" item="id" open="(" separator="," close=")">#{id}</foreach>
</select>

4.2 List 集合参数

Mapper 接口

java

运行

// 根据ID列表查询
List<User> getUserByIdList(@Param("idList") List<Integer> idList);

映射文件

xml

<select id="getUserByIdList" resultType="User">SELECT * FROM user WHERE id IN <foreach collection="idList" item="id" open="(" separator="," close=")">#{id}</foreach>
</select>

foreach 标签属性说明

  • collection:集合参数名称
  • item:循环变量名
  • open:开始符号
  • separator:分隔符
  • close:结束符号
  • index:索引变量名(可选)

4.3 Map 参数

当参数较多且无合适实体类时,可使用 Map 传递参数:

Mapper 接口

java

运行

// 使用Map查询
List<User> getUserByMap(@Param("params") Map<String, Object> params);

映射文件

xml

<select id="getUserByMap" resultType="User">SELECT * FROM user <where><if test="params.username != null">AND username LIKE CONCAT('%', #{params.username}, '%')</if><if test="params.age != null">AND age = #{params.age}</if></where>
</select>

使用示例

java

运行

Map<String, Object> params = new HashMap<>();
params.put("username", "张");
params.put("age", 20);
List<User> users = userMapper.getUserByMap(params);

五、高级参数处理:ResultMap 与复杂对象映射

当数据库表字段与 Java 对象属性名不一致时,需要使用ResultMap进行自定义映射。

5.1 字段与属性名不一致问题

数据库表字段user_nameuser_ageJava 对象属性usernameage

5.2 使用 ResultMap 解决映射问题

映射文件

xml

<!-- 定义ResultMap -->
<resultMap id="UserResultMap" type="User"><id property="id" column="id"/><result property="username" column="user_name"/><result property="age" column="user_age"/><result property="email" column="email"/>
</resultMap><!-- 使用ResultMap -->
<select id="getUserById" resultMap="UserResultMap">SELECT id, user_name, user_age, email FROM user WHERE id = #{id}
</select>

说明

  • id标签用于映射主键
  • result标签用于映射普通字段
  • property:Java 对象属性名
  • column:数据库表字段名

5.3 关联查询映射

处理一对一、一对多关系时的参数传递:

一对一映射

xml

<resultMap id="OrderResultMap" type="Order"><id property="id" column="id"/><result property="orderNo" column="order_no"/><!-- 关联用户对象 --><association property="user" javaType="User"><id property="id" column="user_id"/><result property="username" column="username"/></association>
</resultMap>

一对多映射

xml

<resultMap id="UserOrderResultMap" type="User"><id property="id" column="id"/><result property="username" column="username"/><!-- 关联订单列表 --><collection property="orders" ofType="Order"><id property="id" column="order_id"/><result property="orderNo" column="order_no"/></collection>
</resultMap>

六、参数传递的安全问题:#{} 与 ${} 的区别

MyBatis 提供两种参数占位符:#{}${},它们的区别直接关系到 SQL 安全。

6.1 #{}:预编译处理

  • 会将参数替换为?,进行预编译
  • 自动处理类型转换
  • 防止 SQL 注入
  • 适用于大多数参数传递场景

示例

xml

SELECT * FROM user WHERE username = #{username}

编译后

sql

SELECT * FROM user WHERE username = ?

6.2 ${}:字符串替换

  • 直接替换字符串,不进行预编译
  • 存在 SQL 注入风险
  • 适用于动态表名、排序字段等场景

示例

xml

SELECT * FROM ${tableName} ORDER BY ${column} ${order}

替换后

sql

SELECT * FROM user ORDER BY age DESC

6.3 安全使用 ${} 的场景

  1. 动态表名

xml

<select id="getByTable" resultType="User">SELECT * FROM ${tableName} WHERE id = #{id}
</select>
  1. 动态排序

xml

<select id="getAllOrderBy" resultType="User">SELECT * FROM user ORDER BY ${column} ${direction}
</select>

安全建议

  • ${}参数进行白名单校验
  • 避免直接使用用户输入作为${}参数
  • 优先使用#{},仅在必要时使用${}

七、参数传递最佳实践

  1. 保持参数数量精简

    • 超过 3 个参数时,考虑封装为实体类
    • 零散参数较多时,使用 Map 或 DTO 对象
  2. 始终使用 @Param 注解

    • 提高代码可读性
    • 避免参数顺序变化导致的错误
  3. 合理使用 ResultMap

    • 字段名与属性名不一致时必须使用
    • 关联查询时显式定义映射关系
  4. 防止 SQL 注入

    • 优先使用#{}
    • ${}参数进行严格校验
  5. 复杂参数的文档说明

    • 对 Map 参数和复杂对象添加注释
    • 说明每个参数的含义和用途

八、常见问题与解决方案

  1. Parameter 'xxx' not found

    • 检查是否缺少@Param注解
    • 确保@Param值与#{}中的名称一致
  2. 无效的参数类型转换

    • 检查参数类型与数据库字段类型是否匹配
    • 考虑使用类型处理器(TypeHandler)
  3. 关联查询结果为 null

    • 检查ResultMap中的关联配置
    • 确保 JOIN 查询的关联条件正确
  4. SQL 注入漏洞

    • ${}替换为#{}
    • 对动态参数进行白名单验证

总结

参数传递是 MyBatis 开发中的基础而重要的环节,本文详细介绍了各种参数类型的传递方式,包括基本类型、对象、集合等,以及ResultMap的使用和 SQL 安全问题。掌握这些知识,能够帮助你处理各种复杂的参数场景,编写安全、高效的 MyBatis 代码。在实际开发中,应根据具体业务场景选择合适的参数传递方式,并始终注意 SQL 安全问题。

http://www.dtcms.com/a/393333.html

相关文章:

  • ego(8)---L-BFGS优化算法与B样条生成最终轨迹
  • 【开题答辩全过程】以 HPV疫苗预约网站为例,包含答辩的问题和答案
  • Linux网络中Socket网络套接字的高级应用与优化策略
  • 人才测评系统选型参考:含国内平台对比
  • 人才素质测评在线测评系统平台清单:5款推荐
  • 【语法进阶】匹配分组
  • 猫头虎AI开源项目分享:通过压缩-感知-扩展来改善RAG应用延迟的高效框架:REFRAG,速度快、质量高
  • 某音a_bogus纯算法192位研究分析
  • RAG vs 长文本模型:技术原理、适用场景与选型指南
  • PowerBI自定义函数
  • FreeRTOS——信号量,互斥锁,临界区,延时
  • 第三章 模型评估与优化技巧
  • 3.Spring AI的工具调用
  • 如何高效记单词之:学会想像——从字母W聊起
  • Python之Excel操作三:读取Excel文件中的某一列
  • 计网基础知识
  • 【CSP-J模拟题 】 附详细讲解
  • FPGA内实现FIR 抽取滤波器设计
  • 【proteus绿灯5s红灯10s三数码管数字切换电路】2022-12-12
  • 团队任务分配管理软件平台对比测评
  • 集成学习智慧:为什么Bagging(随机森林)和Boosting(XGBoost)效果那么好?
  • 计算机英语缩写
  • 国轩高科校招社招网申线上测评笔试题库结构说明书(适用于研发/工程/职能全部岗位)
  • 3.2.10 虚拟内存管理 (答案见原书 P238)
  • 算法 --- BFS 解决最短路问题
  • Photoshop蒙版的操作
  • cocos shader敌人受到攻击改变颜色
  • cd论文精读
  • USBD_malloc 禁止替换成 malloc 函数
  • 功能测试与测试用例设计方法详解