侧边栏壁纸
博主头像
colo

欲买桂花同载酒

  • 累计撰写 1823 篇文章
  • 累计收到 0 条评论

MyBatis中#{}和${}的区别是什么?

2025-12-9 / 0 评论 / 4 阅读

题目

MyBatis中#{}和${}的区别是什么?

信息

  • 类型:问答
  • 难度:⭐

考点

参数占位符,SQL注入,动态SQL

快速回答

在MyBatis中,#{}和${}都是参数占位符,但有以下核心区别:

  • #{}:使用预编译处理,能防止SQL注入,会自动添加引号处理字符串
  • ${}:直接拼接SQL字符串,有SQL注入风险,需手动处理引号
  • 使用场景:#{}适用于值传递(如WHERE条件),${}适用于动态表名/列名
## 解析

1. 核心原理

#{} 工作原理

  • MyBatis会将其转换为JDBC的PreparedStatement参数占位符(?)
  • 执行时通过setXxx()方法安全设置参数值
  • 示例:SELECT * FROM user WHERE name = #{name} → 编译为 SELECT * FROM user WHERE name = ?

${} 工作原理

  • 直接进行字符串替换(文本替换)
  • 生成原生SQL语句
  • 示例:SELECT * FROM ${tableName} → 替换为 SELECT * FROM orders

2. 代码示例对比

<!-- 安全用法 -->
<select id="findUser" resultType="User">
  SELECT * FROM user WHERE name = #{name}
</select>

<!-- 风险用法(需手动过滤) -->
<select id="dynamicTable" resultType="map">
  SELECT * FROM ${tableName} WHERE status = 1
</select>

3. 最佳实践

  • 优先使用#{}: 适用于所有值传递场景(WHERE条件、INSERT值等)
  • 谨慎使用${}: 仅用于动态表名/列名等非值场景
  • 防注入措施: 使用${}时必须对传入参数白名单校验:
    // 示例:表名白名单校验
    private static final Set<String> SAFE_TABLES = Set.of("users","orders");
    
    public List<Map> queryTable(String tableName) {
      if(!SAFE_TABLES.contains(tableName)) {
        throw new IllegalArgumentException("Invalid table name");
      }
      return sqlSession.selectList("dynamicTable", tableName);
    }

4. 常见错误

  • 混淆使用场景: 在WHERE条件中使用${}导致SQL注入风险
  • 引号处理错误: ${}用于字符串时忘记加单引号:
    -- 错误写法(导致语法错误)
    WHERE name = ${name}
    
    -- 正确写法
    WHERE name = '${name}'
  • 未做参数校验: 动态表名未校验直接拼接

5. 扩展知识

  • 预编译优势: #{}生成的预编译SQL可被数据库缓存,提高执行效率
  • Like查询处理: 模糊查询应使用CONCAT函数:
    WHERE name LIKE CONCAT('%', #{keyword}, '%')
  • OGNL表达式: #{}内可调用Java方法(如#{name.toUpperCase()}