Mybatis里面#和$区别
原创
2025-03-17 09:24
3
# Mybatis里面#和$区别 ## **1. `#` 的本质是占位符,安全性来源于预编译** ### **过程** - 当使用 `#` 时,MyBatis 不会直接将参数的值拼接到 SQL 中,而是将它替换为一个占位符(`?`)。 - 然后,通过 JDBC 的 预编译机制 ,SQL 和参数会分开处理: - SQL 发送到数据库,先编译。 - 参数通过绑定的形式传递到编译好的 SQL 模板中。 这保证了 SQL 语句的逻辑与参数分离,参数只是数据,而不会影响 SQL 本身。 ### **示例** 假设用户输入了一个恶意参数: ```mysql 1 OR 1=1 ``` 代码: ```mysql @Select("SELECT * FROM users WHERE id = #{id}") ``` 生成的 SQL 是: ```mysql SELECT * FROM users WHERE id = ? ``` 然后,JDBC 会将 `1 OR 1=1` 作为 **一个值**,传递给占位符 `?`: ```mysql SELECT * FROM users WHERE id = '1 OR 1=1' ``` 数据库将这个输入视为字符串,而不是 SQL 逻辑,从而有效避免 SQL 注入。 ------ ## **2. `$` 是字符串替换,直接拼接有风险** ### **过程** - `$` 不会进行任何预编译处理。 - MyBatis 会直接将参数的值替换到 SQL 中,这意味着传入的值会成为 SQL 的一部分。 - 如果参数中包含恶意代码,就会导致 SQL 注入。 ### **示例** 使用 `$` 的代码: ```mysql @Select("SELECT * FROM users WHERE id = ${id}") ``` 假设用户输入了恶意参数: ```mysql 1 OR 1=1 ``` 生成的 SQL 是: ```mysql SELECT * FROM users WHERE id = 1 OR 1=1 ``` 这是一条有效的 SQL 注入语句,结果会返回所有用户数据,而不是特定用户。 ------ ## **3. 最终 SQL 为什么不同?** `#` 和 `$` 的区别在于: - **`#` 的参数在 SQL 之外被处理**:预编译阶段,参数是绑定到占位符的,参数值对 SQL 的逻辑没有任何影响。 - **`$` 的参数直接被插入 SQL**:这是一个简单的字符串拼接,没有任何安全保护。 ### **核心区别:** - **`#` 是参数绑定**,生成的 SQL 是: ```mysql SELECT * FROM users WHERE id = ? ``` 参数值是通过绑定传递的,哪怕参数值是恶意代码,也只会被视为普通数据。 - **`$` 是字符串替换**,生成的 SQL 是: ```mysql SELECT * FROM users WHERE id = 1 OR 1=1 ``` 参数值直接成为了 SQL 的一部分,可以改变 SQL 的逻辑。 ------ ## **4. 使用场景区分** - **`#`:动态值**(安全优先) 适合大部分场景,如传递用户输入的查询条件或值。 - **`$`:动态 SQL 结构**(慎用) 仅用于需要动态拼接字段名、表名等不可预编译的情况。例如: ```mysql SELECT ${column} FROM ${table} WHERE id = #{id} ``` ------ ## **总结** - 虽然最终的 SQL 是完整的,但使用 `#` 时,参数作为**安全的绑定数据**进入 SQL;而使用 `$` 时,参数是直接拼接的,容易被恶意利用。 - **在 MyBatis 开发中,优先使用 `#`,只有在必要的动态结构场景中使用 `$`,并确保输入可信!**
评 论
目录