Mybatis参数传递方法小结
一、 单个参数
这是最简单的情况,当 Mapper 接口方法只有一个参数时。
- 描述: 可以是 Java 的基本类型 (int, float, boolean 等)、包装类型 (Integer, Float, Boolean 等)、String 类型,也可以是一个复杂的 Java Bean 对象 (
POJO
)。 - XML 中引用: 在 XML 文件中,你可以使用
#{任意名称}
来引用这个参数。MyBatis 不关心#{}
里面的名字是什么(虽然推荐使用有意义的名字,比如参数本身的名称)。对于 POJO 对象作为单个参数,可以直接使用#{propertyName}
来引用其属性。
示例:
- Mapper 接口:
package com.example.mapper;
import com.example.model.User;
public interface UserMapper {
// 根据 ID 查询用户 (基本类型包装类)
User findUserById(Integer id);
// 根据 Email 查询用户 (String 类型)
User findUserByEmail(String email);
// 更新用户信息 (POJO 作为单个参数)
int updateUserDetails(User user);
}
- XML 映射文件 (UserMapper.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.UserMapper">
<select id="findUserById" resultType="com.example.model.User">
SELECT id, username, email FROM users WHERE id = #{userId} </select>
<select id="findUserByEmail" resultType="com.example.model.User">
SELECT id, username, email FROM users WHERE email = #{emailAddress} </select>
<update id="updateUserDetails">
UPDATE users
SET username = #{username}, email = #{email} WHERE id = #{id}
</update>
</mapper>
二、 多个参数
当 Mapper 接口方法有多个参数时,MyBatis 需要知道如何在 XML 中引用它们。有以下几种常用方式:
1. 使用参数索引 (不推荐)
-
描述: 在较旧的 MyBatis 版本或者特定配置下,可以通过参数在方法签名中的顺序(从 0 开始)来引用。形式为
#{0}
,#{1}
… 或者#{param1}
,#{param2}
…。 -
缺点: 可读性差,容易出错,依赖于参数顺序,不推荐在现代开发中使用。MyBatis 3.4.1 默认
useActualParamName
为true
,使得基于@Param
或参数实际名称的方式成为主流。
示例 (仅作了解,不推荐使用):
- Mapper 接口:
User findUserByNameAndDept(String name, String department);
- XML 映射文件:
<select id="findUserByNameAndDept" resultType="com.example.model.User">
SELECT * FROM users WHERE username = #{0} AND department = #{1}
</select>
2.使用 @Param
注解 (推荐)
-
描述: 这是处理多个参数最清晰、最推荐的方式。通过在 Mapper 接口方法的参数前添加 @Param(“自定义名称”) 注解,可以明确指定每个参数在 XML 中引用的名称。
-
原理: MyBatis 会将带有 @Param 注解的参数封装到一个 Map<String, Object> 中,Map 的 key 就是 @Param 注解中指定的字符串,value 就是对应的参数值。XML 中通过 #{注解指定的名称} 来引用。
示例:
- Mapper 接口:
import org.apache.ibatis.annotations.Param;
// ... 其他 import
public interface UserMapper {
User findUserByNameAndDept(@Param("userName") String name, @Param("deptName") String department);
}
- XML 映射文件:
<select id="findUserByNameAndDept" resultType="com.example.model.User">
SELECT id, username, email, department
FROM users
WHERE username = #{userName} AND department = #{deptName} </select>
3. 使用 Map
-
描述: 将所有参数放入一个 Map 对象中,然后将这个 Map 作为 单个参数 传递给 Mapper 接口方法。
-
优点: 灵活,适用于参数个数不确定或参数较多的情况。
-
XML 中引用: 直接使用
#{mapKey}
来引用 Map 中的值。
示例:
- Mapper 接口:
import java.util.Map;
// ... 其他 import
public interface UserMapper {
User findUserByCriteria(Map<String, Object> criteria);
}
- 调用代码:
Map<String, Object> params = new HashMap<>();
params.put("nameParam", "John Doe");
params.put("deptParam", "Sales");
User user = userMapper.findUserByCriteria(params);
- XML 映射文件:
<select id="findUserByCriteria" resultType="com.example.model.User">
SELECT id, username, email, department
FROM users
WHERE username = #{nameParam} AND department = #{deptParam} </select>
4. 使用 POJO (Java Bean)
-
描述: 将所有相关的参数封装到一个自定义的 Java 对象 (POJO 或 DTO) 中,然后将这个对象作为 单个参数 传递给 Mapper 接口方法。
-
优点: 结构清晰,代码可读性好,特别适合参数代表一个业务实体或数据传输单元的情况 (如插入、更新操作)。
-
XML 中引用: 使用
#{propertyName}
来引用 POJO 的属性。
示例:
- Mapper 接口:
package com.example.param;
public class UserQueryParam {
private String name;
private String department;
// Getters and Setters...
// Constructor(s)...
}
- Mapper 接口:
import com.example.param.UserQueryParam;
// ... 其他 import
public interface UserMapper {
User findUserByPojo(UserQueryParam queryParam);
}
- XML 映射文件:
<select id="findUserByPojo" resultType="com.example.model.User">
SELECT id, username, email, department
FROM users
WHERE username = #{name} AND department = #{department} </select>
三、 List 传参
-
描述: 当你需要传递一个列表(例如,用于 SQL 的 IN 子句)时,可以将
java.util.List
作为参数传递。 -
处理方式: 通常在 XML 中结合
<foreach>
标签来遍历List
中的元素。如果List
是唯一的参数,可以直接在<foreach>
的collection
属性中写list
;如果是多个参数中的一个,强烈建议使用@Param
为List
指定一个明确的名称。
示例:
- Mapper 接口:
import java.util.List;
import org.apache.ibatis.annotations.Param;
// ... 其他 import
public interface UserMapper {
List<User> findUsersByIdList(@Param("userIds") List<Integer> idList);
}
- XML 映射文件:
<select id="findUsersByIdList" resultType="com.example.model.User">
SELECT id, username, email
FROM users
WHERE id IN
<foreach item="singleId" collection="userIds" open="(" separator="," close=")">
#{singleId}
</foreach>
</select>
这里
foreach
表示循环操作,具体的参数含义如下:
foreach
元素的属性主要有item
,index
,collection
,open
,separator
,close
。
item
表示集合中每一个元素进行迭代时的别名,index
指定一个名字,用于表示在迭代过程中,每次迭代到的位置,open
表示该语句以什么开始,separator
表示在每次进行迭代之间以什么符号作为分隔符,close
表示以什么结束注意:
在使用foreach的时候最关键的也是最容易出错的就是
collection
属性,该属性是必须指定的,但是在不同情况下,该属性的值是不一样的,主要有一下3种情况:
- 如果传入的是单参数且参数类型是一个
List
的时候,collection
属性值为list
- 如果传入的是单参数且参数类型是一个
array
数组的时候,collection
的属性值为array
- 如果传入的参数是多个的时候,我们就需要把它们封装成一个
Map
或者Object
四、 数组传参
-
描述: 与
List
类似,也可以传递数组作为参数,常用于 IN 子句。 -
处理方式: 和
List
非常相似,同样在XML
中使用<foreach>
标签。如果数组是唯一参数,collection
属性可以直接写array
;如果是多个参数之一,也强烈建议使用@Param
命名。
示例:
- Mapper 接口:
import org.apache.ibatis.annotations.Param;
// ... 其他 import
public interface UserMapper {
List<User> findUsersByIdArray(@Param("idArray") Integer[] ids);
}
- XML 映射文件:
<select id="findUsersByIdArray" resultType="com.example.model.User">
SELECT id, username, email
FROM users
WHERE id IN
<foreach item="idElement" collection="idArray" open="(" separator="," close=")">
#{idElement}
</foreach>
</select>
五、总结与建议
- 单个参数: 直接传递,XML 中用 **
#{任意名称}
**或#{propertyName}
(对于 POJO)。 - 多个简单参数: 强烈推荐使用
@Param
注解为每个参数命名,XML 中用#{注解名}
。- 多个相关参数/结构化参数: 推荐封装成 POJO 或使用 Map 传递,XML 中用
#{propertyName}
或#{mapKey}
。 - 集合参数 (List/数组): 使用
@Param
命名(尤其是有其他参数时),在 XML 中结合<foreach>
标签处理。 - 避免使用 索引传参 (
#{0}
,#{param1}
) 的方式。
- 多个相关参数/结构化参数: 推荐封装成 POJO 或使用 Map 传递,XML 中用
选择哪种方式取决于参数的数量、性质以及个人或团队的编码风格偏好。通常,清晰性和可维护性是首要考虑因素,因此 @Param
和 POJO
是最常用的方式。
参考: