MyBatis 如何处理参数:
- 参数解析: 当 MyBatis 执行 SQL 语句时,它会解析 SQL 语句中的占位符(
#{}或${}),并根据 Mapper 接口方法的参数类型和名称(或@Param注解指定的名称)来查找对应的参数值。 - 类型转换: MyBatis 会使用
TypeHandler将 Java 类型的参数值转换为 JDBC 类型的值。 - 参数绑定: MyBatis 会使用
PreparedStatement对象将参数值绑定到 SQL 语句中的占位符。对于#{}占位符,MyBatis 会使用PreparedStatement的setXXX()方法进行参数绑定,从而防止 SQL 注入;对于${}占位符,MyBatis 会直接将参数值拼接到 SQL 语句中,存在 SQL 注入风险。
MyBatis 支持的参数类型:
MyBatis 支持以下参数类型:
- 基本类型及其包装类:
int,long,float,double,boolean,byte,short,Integer,Long,Float,Double,Boolean,Byte,Short。 - String: 字符串类型。
- Date:
java.util.Date、java.sql.Date、java.sql.Time、java.sql.Timestamp。 - BigDecimal: 高精度数字类型。
- 数组: 基本类型数组或对象数组。
- 集合:
List、Set、Map。 - JavaBean (POJO): 普通 Java 对象。
- 枚举类型: 默认使用枚举的名称或序数(可以通过自定义
TypeHandler来改变)。 null: 如果传递的是null值, 并且MyBatis无法推断, 则必须指定jdbcType属性。
传递多个参数的方式:
MyBatis 提供了多种方式来传递多个参数:
-
使用
@Param注解 (推荐):- 在 Mapper 接口方法的参数列表中,使用
@Param注解为每个参数指定一个名称。 - 在 SQL 映射文件中,使用
#{}占位符引用参数时,使用@Param注解指定的名称。
// Mapper 接口 public interface UserMapper { List<User> selectUsersByNameAndAge(@Param("name") String name, @Param("age") int age); } <!-- SQL 映射文件 --> <select id="selectUsersByNameAndAge" resultType="com.example.model.User"> SELECT * FROM users WHERE name LIKE #{name} AND age > #{age} </select> - 在 Mapper 接口方法的参数列表中,使用
-
使用 Map:
- 将多个参数封装到一个
Map对象中。 - 在 SQL 映射文件中,使用
#{}占位符引用参数时,使用Map中的 key 作为参数名称。
// Mapper 接口 public interface UserMapper { List<User> selectUsersByMap(Map<String, Object> params); } // 调用示例 Map<String, Object> params = new HashMap<>(); params.put("name", "John%"); params.put("age", 30); List<User> users = userMapper.selectUsersByMap(params); <!-- SQL 映射文件 --> <select id="selectUsersByMap" resultType="com.example.model.User"> SELECT * FROM users WHERE name LIKE #{name} AND age > #{age} </select> - 将多个参数封装到一个
-
使用 JavaBean (POJO):
- 将多个参数封装到一个 JavaBean 对象中。
- 在 SQL 映射文件中,使用
#{}占位符引用参数时,使用 JavaBean 对象的属性名作为参数名称。
// JavaBean public class UserQuery { private String name; private int age; // getter 和 setter 方法 } // Mapper 接口 public interface UserMapper { List<User> selectUsersByQuery(UserQuery query); } // 调用示例 UserQuery query = new UserQuery(); query.setName("John%"); query.setAge(30); List<User> users = userMapper.selectUsersByQuery(query); <!-- SQL 映射文件 --> <select id="selectUsersByQuery" resultType="com.example.model.User"> SELECT * FROM users WHERE name LIKE #{name} AND age > #{age} </select> -
使用参数索引 (不推荐):
- 如果不使用
@Param注解,MyBatis 会按照参数在方法参数列表中的顺序,为参数分配索引(从 0 开始)。 - 在 SQL 映射文件中,可以使用
#{0},#{1},#{param1},#{param2}等方式引用参数。 这种方式不够直观,容易出错,不推荐使用。
- 如果不使用
# 和 $ 占位符的区别:
-
#{}(预编译参数):- MyBatis 会使用
PreparedStatement的setXXX()方法将参数值绑定到 SQL 语句中的占位符。 - 优点:
- 防止 SQL 注入:
PreparedStatement会对参数值进行转义,有效防止 SQL 注入攻击。 - 类型安全: MyBatis 会根据参数类型选择合适的
setXXX()方法,避免类型转换错误。 - 性能更好:
PreparedStatement可以预编译 SQL 语句,对于重复执行的 SQL 语句,性能更好。
- 防止 SQL 注入:
- 适用场景: 绝大多数情况,推荐使用
#{}。
- MyBatis 会使用
-
${}(字符串替换):- MyBatis 会直接将参数值拼接到 SQL 语句中。
- 缺点:
- SQL 注入风险: 如果参数值来自用户输入,直接使用
${}拼接 SQL 语句会导致 SQL 注入漏洞。 - 类型不安全: MyBatis 不会进行类型转换,可能导致类型错误。
- SQL 注入风险: 如果参数值来自用户输入,直接使用
- 适用场景:
- 动态表名或列名: 当需要动态指定表名或列名时,可以使用
${}。 - IN 语句: 当需要将一个集合作为 IN 语句的参数时,可以使用
${}(但更推荐使用<foreach>标签)。 - ORDER BY: 当需要动态指定排序字段时, 可以使用
${}
- 动态表名或列名: 当需要动态指定表名或列名时,可以使用
<!-- 动态表名 (谨慎使用) --> <select id="selectFromTable" resultType="com.example.model.User"> SELECT * FROM ${tableName} WHERE id = #{id} </select> <!-- IN 语句 (更推荐使用 <foreach> 标签) --> <select id="selectUsersByIds" resultType="com.example.model.User"> SELECT * FROM users WHERE id IN (${ids}) </select>
总结:
- MyBatis 支持多种参数类型,包括基本类型、String、Date、BigDecimal、数组、集合、JavaBean、枚举类型等。
- 传递多个参数的推荐方式是使用
@Param注解。 #{}是预编译参数,可以防止 SQL 注入,类型安全,性能更好,推荐使用。${}是字符串替换,存在 SQL 注入风险,类型不安全,谨慎使用,仅在需要动态表名、列名或 IN 语句等特殊场景下使用。- 传递
null值, 并且MyBatis无法推断, 则必须指定jdbcType属性。

1100

被折叠的 条评论
为什么被折叠?



