14. /#{} 和 /${} 的区别是什么?

在MyBatis中,#{}${}是两种常见的占位符,它们的作用和使用场景有所不同。理解它们的区别对于正确使用MyBatis非常重要。

1. #{} 和 ${} 的基本区别

#{}:SQL参数占位符

  • 作用#{}用于将传入的参数安全地绑定到SQL语句中,它会自动使用PreparedStatement?占位符机制,并且MyBatis会对传入的参数进行预处理(例如防止SQL注入)。

  • 参数替换 :在生成SQL语句时,#{}会被替换为一个?,然后由JDBC驱动程序将参数值绑定到这个?占位符上。

  • 使用场景:通常用于传递用户输入的参数,如查询条件、插入或更新的数据等。

    示例

    java 复制代码
    <select id="findUserById" resultType="User">
        SELECT * FROM users WHERE id = #{id}
    </select>
    • 如果传入的id为1,MyBatis生成的SQL类似于:SELECT * FROM users WHERE id = ?,然后通过PreparedStatement?替换为1。

${}:SQL文本占位符

  • 作用${}用于直接将传入的参数值替换到SQL语句中,它不会进行预处理,因此直接将参数值插入到SQL语句中。这意味着${}会将参数视为SQL的一部分,可能会导致SQL注入风险。

  • 参数替换 :在生成SQL语句时,${}会直接将传入的值替换到SQL语句中,而不会使用?占位符。

  • 使用场景:通常用于动态生成SQL片段,比如排序字段名、表名、列名等不直接来自用户输入的参数。

    示例

    java 复制代码
    <select id="findUserByColumn" resultType="User">
        SELECT * FROM users WHERE ${columnName} = #{value}
    </select>
    • 如果传入的columnNameusernamevalueJohn,MyBatis生成的SQL类似于:SELECT * FROM users WHERE username = ?,然后通过PreparedStatement?替换为John

2. 安全性和使用建议

  • SQL注入防护 :由于#{}会使用PreparedStatement的参数绑定机制,因此可以有效防止SQL注入攻击。而${}直接将参数值拼接到SQL中,可能导致SQL注入,因此应慎重使用。

  • 动态SQL生成${}更适合用于生成动态的SQL片段,比如动态表名、列名等。但要确保传入的值是可信任的,或者通过其他手段确保安全。

3. 具体示例

使用 #{} 的示例

java 复制代码
<select id="findUserById" resultType="User">
    SELECT * FROM users WHERE id = #{id}
</select>
  • 传入id为1,生成SQL为:

    java 复制代码
    SELECT * FROM users WHERE id = ?

    然后将参数1安全地绑定到?上。

使用 ${} 的示例

java 复制代码
<select id="findUserByColumn" resultType="User">
    SELECT * FROM users WHERE ${columnName} = #{value}
</select>
  • 传入columnNameusernamevalueJohn,生成SQL为:

    java 复制代码
    SELECT * FROM users WHERE username = ?

    然后将参数John绑定到?上。

SQL注入风险示例

java 复制代码
<select id="findUserByColumn" resultType="User">
    SELECT * FROM users WHERE ${columnName} = #{value}
</select>
  • 如果传入的columnNameusername OR '1'='1',生成的SQL可能是:

    java 复制代码
    SELECT * FROM users WHERE username OR '1'='1' = ?

    这样就可能导致SQL注入问题。

总结

  • #{}:安全地传递参数,防止SQL注入,常用于传递用户输入的参数。

  • ${}:直接将参数值插入到SQL中,适用于动态生成SQL片段(如表名、列名),但存在SQL注入风险,应谨慎使用。

在实际开发中,建议尽量使用#{}来传递参数,以确保SQL安全性,而对于使用${}的场景,需要确保传入的参数是安全且经过验证的。

相关推荐
风象南3 分钟前
SpringBoot 控制器的动态注册与卸载
java·spring boot·后端
醇醛酸醚酮酯21 分钟前
Qt项目锻炼——TODO清单(二)
开发语言·数据库·qt
jioulongzi27 分钟前
记录一次莫名奇妙的跨域502(badgateway)错误
开发语言·python
我是一只代码狗29 分钟前
springboot中使用线程池
java·spring boot·后端
hello早上好42 分钟前
JDK 代理原理
java·spring boot·spring
PanZonghui1 小时前
Centos项目部署之Java安装与配置
java·linux
向阳@向远方1 小时前
第二章 简单程序设计
开发语言·c++·算法
沉着的码农1 小时前
【设计模式】基于责任链模式的参数校验
java·spring boot·分布式
Mr_Xuhhh1 小时前
信号与槽的总结
java·开发语言·数据库·c++·qt·系统架构
纳兰青华2 小时前
bean注入的过程中,Property of ‘java.util.ArrayList‘ type cannot be injected by ‘List‘
java·开发语言·spring·list