mybatis 参数为list时,校验list是否为空, mybatis ${}与#{}的区别

一、参数list时,先判断是否为空,否则会报错。

二、mybatis ${}与#{}的区别

简单来说#{} 解析的是占位符?可以防止SQL注入, 比如打印出来的语句 select * from table where id=?
然而${} 则是不能防止SQL注入打印出来的语句 select * from table where id=2  实实在在的参数。
最简单的区别就是${}解析穿过来的参数值不带单引号,#{}解析传过来参数带单引号。
最后总结一下必须使用$引用参数的情况,那就是参数的int型的时候,必须使用$引用。



<think>我们在使用MyBatis,经常会看到动态SQL中用到`#{}`和`${}`两种占位符。它们的主要区别在于参数替换的方式和安全性。 1. `#{}`: 是预编译处理,MyBatis会将`#{}`替换为`?`,然后使用PreparedStatement的set方法来赋值,可以有效防止SQL注入,适用于传入参数值。 2. `${}`: 是字符串替换,MyBatis会将`${}`替换为变量的实际值,相当于直接拼接SQL字符串,存在SQL注入风险,一般用于传入SQL片段(如表名、列名等动态变化的部分)。 举例说明: 假设我们有一个查询:`select * from user where name = #{name}` 实际执行MyBatis会生成:`select * from user where name = ?`,然后通过PreparedStatement的setString(1, name)来设置参数。 而如果使用:`select * from user where name = ${name}` 如果传入的name是`&#39;John&#39;`,那么实际执行的SQL为:`select * from user where name = &#39;John&#39;`。 但如果传入的name是`&#39; or 1=1 -- `,那么使用`${}`就会导致SQL注入:`select * from user where name = &#39;&#39; or 1=1 -- &#39;`,从而查询到所有数据。 因此,一般规则是: - 能用`#{}`的地方尽量用`#{}` - 对于表名、列名等无法使用预编译的地方,使用`${}`,但需要对外部输入进行严格的校验和过滤。 下面是一个简单的代码示例,展示MyBatis中两种占位符的用法: 假设有一个Mapper接口: ```java public interface UserMapper { // 使用#{}安全地传入参数 @Select("SELECT * FROM users WHERE name = #{name}") List<User> findByName(@Param("name") String name); // 使用${}动态指定表名(注意:这里存在SQL注入风险,应谨慎使用) @Select("SELECT * FROM ${tableName} WHERE name = #{name}") List<User> findByTableAndName(@Param("tableName") String tableName, @Param("name") String name); } ``` 在第二个方法中,表名是通过`${tableName}`传入的,因此我们需要确保`tableName`的值是安全的(例如,只能是预定义的表名之一)。而`#{name}`则是安全地传入参数。 总结: - `#{}`:预编译,安全,防SQL注入,适用于参数值。 - `${}`:字符串替换,不安全,有SQL注入风险,适用于动态表名、列名等。 §§相关问题§§: 1. MyBatis中`#{}`和`${}`的主要区别是什么? 2. 为什么使用`#{}`可以防止SQL注入? 3. 在什么情况下必须使用`${}`? 4. 如何在使用`${}`防范SQL注入攻击? </think>在 MyBatis 中,`#{}` 和 `${}` 是两种不同的参数占位符,它们的主要区别在于**参数处理方式**和**安全性**,以下是详细对比: --- ### **1. `#{}`(推荐使用)** - **原理**: 使用 `PreparedStatement` 预编译 SQL(即 JDBC 的 `?` 占位符),参数值会被安全地转义处理。 - **安全性**: 天然防止 SQL 注入攻击。 - **适用场景**: 传递**参数值**(如 WHERE 条件值、INSERT/UPDATE 值)。 - **示例**: ```sql SELECT * FROM users WHERE name = #{name} ``` ```java // 实际执行参数值被转义): SELECT * FROM users WHERE name = &#39;Alice&#39; ``` --- ### **2. `${}`(谨慎使用)** - **原理**: 直接替换为字符串(文本替换),无预编译或转义。 - **安全性**: 存在 SQL 注入风险! - **适用场景**: 动态拼接 **SQL 片段**(如表名、列名、动态排序字段等)。 - **示例**: ```sql SELECT * FROM ${tableName} ORDER BY ${sortField} ``` ```java // 实际执行(直接替换字符串): SELECT * FROM users ORDER BY create_time ``` --- ### **关键区别总结** | 特性 | `#{}` | `${}` | |--------------|--------------------------------|--------------------------------| | **处理方式** | 预编译(`?` 占位符) | 字符串直接替换 | | **安全性** | ✅ 防 SQL 注入 | ❌ 有 SQL 注入风险 | | **常见用途** | 传递参数值 | 动态 SQL 片段(表名、列名等) | | **性能** | 相同(预编译后均可复用执行计划) | 相同 | --- ### **为什么 `${}` 有 SQL 注入风险?** 假设动态传入表名: ```sql SELECT * FROM ${tableName} ``` 如果外部传入 `tableName = "users; DROP TABLE users--"`,最终 SQL 会变成: ```sql SELECT * FROM users; DROP TABLE users-- ``` 这将直接删除表!而 `#{}` 会将整个字符串视为表名值(语法错误),不会执行破坏性操作。 --- ### **最佳实践** 1. **99% 的场景用 `#{}`**: 传递条件值、字段值等。 2. **谨慎使用 `${}`**: 仅在动态表名/列名等**非值参数**使用,且必须手动校验参数合法性(如白名单校验)。 ```java // 示例:安全使用 ${}(校验表名合法性) public List<User> getUsers(@Param("table") String table) { if (!Arrays.asList("users", "admins").contains(table)) { throw new IllegalArgumentException("Invalid table name"); } return sqlSession.selectList("getUsersByTable", table); } ``` --- ### **代码示例** ```java // Mapper 接口 public interface UserMapper { // 安全:使用 #{} 传递参数值 @Select("SELECT * FROM users WHERE name = #{name}") List<User> selectByName(@Param("name") String name); // 动态排序(需谨慎校验 sortField) @Select("SELECT * FROM users ORDER BY ${sortField}") List<User> selectWithSort(@Param("sortField") String sortField); } ``` ---
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值