MySQL 中 `${}` 和 `#{}` 占位符详解及面试高频考点

文章目录

    • 一、概述
    • 二、`#{}` 和 `${}` 的核心区别
      • 1. 底层机制
        • 代码示例
      • 2. 核心区别总结
    • 三、为什么表名只能用 `${}`?
      • 1. 预编译机制的限制
      • 2. 动态表名的实现
    • 四、安全性注意事项
      • 1. `${}` 的风险场景
      • 2. 安全实践
    • 五、面试高频考点
      • 1. 基础原理类问题
        • **问题 1**:
        • **问题 2**:
      • 2. 安全与设计类问题
        • **问题 3**:
        • **问题 4**:
      • 3. 扩展实战类问题
        • **问题 5**:
    • 六、总结与最佳实践
      • 1. 使用场景对比
      • 2. 最佳实践
    • 七、附录:MyBatis 预编译原理图示

一、概述

在 MySQL 和 MyBatis 等框架中,${}#{} 是动态 SQL 中常用的占位符。它们的核心差异在于 预编译机制安全性,正确使用二者是后端开发的基本功,也是面试中的高频考点。本文将从原理、场景、安全性及面试题四方面深入解析。


二、#{}${} 的核心区别

1. 底层机制

占位符预编译替换方式安全性
#{}参数化绑定 (?)
${}字符串直接拼接
代码示例
-- #{}
SELECT * FROM users WHERE name = #{name};
-- 预编译后:SELECT * FROM users WHERE name = ?;-- ${}
SELECT * FROM ${table} WHERE id = 1;
-- 替换后:SELECT * FROM users_2023 WHERE id = 1;

2. 核心区别总结

  • #{}
    用于替换 值类型(如 WHERE 条件值、INSERT 字段值),通过 PreparedStatement 预编译,防止 SQL 注入。
  • ${}
    用于替换 标识符(如表名、列名、ORDER BY 子句),直接拼接字符串,需手动校验安全性。

三、为什么表名只能用 ${}

1. 预编译机制的限制

  • 数据库协议限制:预编译占位符 ? 仅支持替换值类型(字符串、数字等),不能替换表名、列名等标识符。
  • 语法合法性:以下写法直接报错:
    -- 错误!表名无法预编译
    SELECT * FROM ? WHERE id = 1;
    

2. 动态表名的实现

若需根据业务逻辑动态切换表(如分表场景),只能通过字符串拼接:

<!-- MyBatis 示例 -->
<select id="selectLogs" resultType="Log">SELECT * FROM logs_${month}
</select>

四、安全性注意事项

1. ${} 的风险场景

// 恶意输入导致 SQL 注入
String userInput = "users; DROP TABLE users; --";
String sql = "SELECT * FROM " + userInput; 
// 执行结果:SELECT * FROM users; DROP TABLE users; --

2. 安全实践

  1. 禁止用户控制表名:表名应在代码层生成(如根据时间分表),而非直接传递用户输入。
  2. 白名单校验:若必须动态传参,需校验参数格式(如正则匹配 ^[a-zA-Z0-9_]+$)。
  3. SQL 审计:拦截非常规表名操作(如 information_schema)。

五、面试高频考点

1. 基础原理类问题

问题 1

“MyBatis 中 #{}${} 的底层实现有什么区别?”

  • #{} 使用 PreparedStatement 预编译,参数替换为 ?,防止 SQL 注入。
  • ${} 直接拼接字符串,无预编译,需手动处理安全性。

场景
面试官考察候选人对 MyBatis 执行过程的理解,是否清楚预编译机制。


问题 2

“为什么表名必须用 ${}?能否用 #{}?”

数据库协议规定预编译占位符 ? 只能替换值类型,不能替换表名、列名等标识符。若强行使用 #{},最终生成的 SQL 会因语法错误无法执行。

场景
面试中常见于考察 SQL 预编译机制的底层知识。


2. 安全与设计类问题

问题 3

“如何安全地使用 ${} 动态指定表名?”

  • 代码层控制:表名由系统生成(如 user_2023),而非用户传入。
  • 白名单校验:若需外部传入,校验参数是否符合命名规范(如正则匹配)。
  • 日志监控:记录所有动态表名操作,便于审计。

场景
考察安全意识和实际工程经验,常见于金融、数据安全相关岗位。


问题 4

“除了表名,还有哪些场景必须用 ${}?”

  • 动态列名:SELECT ${column} FROM table
  • 排序字段:ORDER BY ${sortField}
  • 动态 SQL 片段:<if test="condition">${sqlSegment}</if>

场景
面试官可能延伸考察动态 SQL 的灵活应用能力。


3. 扩展实战类问题

问题 5

“如果必须让用户传入表名,如何设计安全方案?”

  1. 前端传递表名编码(如 1=users, 2=products),后端映射为真实表名。
  2. 参数加密:用户传入加密参数,后端解密后匹配预定义表名。
  3. 数据库权限隔离:动态表操作使用只读低权限账号。

场景
高级岗位考察系统设计能力,尤其是安全与灵活性平衡的方案。


六、总结与最佳实践

1. 使用场景对比

场景占位符示例
WHERE 条件值#{}WHERE id = #{id}
动态表名/列名${}SELECT * FROM ${table}
排序字段${}ORDER BY ${sort}

2. 最佳实践

  • 默认使用 #{}:除非必须使用 ${}
  • 最小化 ${} 暴露:禁止用户传入未经验证的参数。
  • 日志 + 监控:记录所有动态 SQL 操作,及时预警异常行为。

七、附录:MyBatis 预编译原理图示

MyBatis 执行流程:
1. 解析 XML SQL → 2. 替换 `#{}` 为 `?` → 3. 预编译 SQL → 4. 绑定参数值 → 5. 执行

文档说明:本文适用于初中级后端开发者巩固知识点,以及资深开发者面试复习。建议结合 MyBatis 源码和 MySQL 协议文档深入理解。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/web/76097.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

C语言编译预处理2

#include <XXXX.h>和#include <XXXX.c> #include "XXXX.h" 是 C 语言中一条预处理指令 #include <XXXX.h>&#xff1a;这种形式用于包含系统标准库的头文件。预处理器会在系统默认的头文件搜索路径中查找XXXX.h 文件。例如在 Linux 系统中&#…

Elasticvue-轻量级Elasticsearch可视化管理工具

Elasticvue一个免费且开源的 Elasticsearch 在线可视化客户端&#xff0c;用于管理 Elasticsearch 集群中的数据&#xff0c;完全支持 Elasticsearch 版本 8.x 和 7.x. 功能特色&#xff1a; 集群概览索引和别名管理分片管理搜索和编辑文档REST 查询快照和存储库管理支持国际…

Git提交规范及最佳实践

Git 提交规范通常是为了提高代码提交的可读性、可维护性和自动化效率&#xff08;如生成 ChangeLog&#xff09;。以下是常见的 Conventional Commits 规范&#xff0c;结合社区最佳实践总结而成&#xff1a; 1. 提交格式 每次提交的 commit message 应包含三部分&#xff1a;…

Ubuntu中snap

通过Snap可以安装众多的软件包。需要注意的是&#xff0c;snap是一种全新的软件包管理方式&#xff0c;它类似一个容器拥有一个应用程序所有的文件和库&#xff0c;各个应用程序之间完全独立。所以使用snap包的好处就是它解决了应用程序之间的依赖问题&#xff0c;使应用程序之…

android studio 运行java main报错

运行某个带main函数的java文件报错 Could not create task :app:Test.main(). > SourceSet with name main not found. 解决办法&#xff1a;在工程的.idea/gradle.xml 文件下添加&#xff1a; <option name"delegatedBuild" value"false" /&g…

openssh离线一键升级脚本分享(含安装包)

查看当前的版本 [rootmyoracle ~]#ssh -V相关安装包下载地址 openssh下载地址&#xff1a;http://ftp.openbsd.org/pub/OpenBSD/OpenSSH/portable/openssl下载地址&#xff1a;https://www.openssl.org/source/zlib下载地址&#xff1a;http://www.zlib.net/今天演示从7.4升级…

Mac M1管理多个Node.js版本

目录 1. 使用 nvm (Node Version Manager) 1.1.安装 nvm 1.2.安装Node.js版本 1.3.查看已安装的node版本列表 1.4.使用特定版本的Node.js 1.5.查看当前使用的版本 2. 使用 fnm (Fast Node Manager) 2.1.安装 fnm 2.2.安装Node.js版本 2.3.查看已安装的版本 2.4.使用…

Unity中国战略调整简讯:Unity6下架 团结引擎接棒

Unity中国战略调整简讯&#xff1a;Unity6下架 团结引擎接棒 免费版 2025年4月9日 —— Unity中国宣布自即日起&#xff0c;中国大陆及港澳地区停止提供Unity 6及后续版本下载与服务&#xff0c;相关功能由国产引擎“团结引擎”承接。国际版2022 LTS及更早版本仍由Unity中国维护…

TestNG 单元测试详解

1、测试环境 jdk1.8.0 121 myeclipse-10.0-offline-installer-windows.exe TestNG 插件 org.testng.eclipse 6.8.6.20130607 0745 2、介绍 套件(suite):由一个 XML 文件表示,通过<suite>标签定义,包含一个或更多测试(test)。测试(test):由<test>定义&#xf…

C复习(主要复习)

指针和数组 指针数组是一个数组&#xff0c;数组的每个元素都是指针。它适用于需要存储多个指针的场景&#xff0c;如字符串数组。数组指针是一个指针&#xff0c;指向一个数组。它适用于需要传递整个数组给函数或处理多维数组的场景。 函数指针&#xff1a;函数指针的定义需要…

探索大语言模型(LLM):定义、发展、构建与应用

文章目录 引言大规模语言模型的基本概念大规模语言模型的发展历程1. 基础模型阶段&#xff08;2018年至2021年&#xff09;2. 能力探索阶段&#xff08;2019年至2022年&#xff09;3. 突破发展阶段&#xff08;以2022年11月ChatGPT的发布为起点&#xff09; 大规模语言模型的构…

5. k8s 之 pod原理与使用

Kubernetes Pod 原理详解 1. Pod 的部署方式 Pod 是 Kubernetes 的最小调度单元&#xff0c;其部署方式分为 声明式&#xff08;YAML&#xff09; 和 命令式&#xff08;kubectl&#xff09; 两种&#xff1a; (1) 声明式部署&#xff08;推荐&#xff09; 通过 YAML 文件定…

使用PyTorch实现目标检测边界框转换与可视化

一、引言 在目标检测任务中&#xff0c;边界框&#xff08;Bounding Box&#xff09;的坐标表示与转换是核心基础操作。本文将演示如何&#xff1a; 实现边界框的两种表示形式&#xff08;角点坐标 vs 中心坐标&#xff09;之间的转换 使用Matplotlib在图像上可视化边界框 验…

电影推荐及数据分析可视化系统(Python+Echarts+Mysql+Flask框架)

提升自己&#xff0c;掌握数据分析的能力&#xff0c;最快的方式就是实践&#xff01; 下面是对本项目的一些功能展示、介绍以及部分核心代码的展示,附项目系统展示的视频,制作不易如需完整代码后台私信我有偿获取! 一 、系统分析及功能介绍 1.系统分析 系统采用Python作为开发…

Android Jetpack Compose 高级开发核心技术

Android Compose 高级技术总结 1. 性能优化 1.1 状态管理优化 状态提升原则&#xff1a;将状态提升到共享的最近共同父组件derivedStateOf&#xff1a;当需要基于多个状态计算派生状态时使用 val scrollState rememberScrollState() val showButton by remember {derivedS…

Java堆结构深度解析:原理、实现与应用全指南

一、堆的核心概念体系 1. 堆的定义与性质 graph TBROOT((最大堆)) --> A[父节点 ≥ 子节点]ROOT --> B[完全二叉树结构]ROOT --> C[数组存储]ROOT --> D[快速获取极值] 2. 堆类型对比 类型特性典型应用场景最大堆父节点值 ≥ 子节点值获取前K大元素最小堆父节点…

SpringMVC学习(请求与响应。常见参数类型接收与响应。@RequestParam、@RequestBody的使用)(详细示例)

目录 一、请求与响应。(RequestMapping) &#xff08;1&#xff09;使用注解RequestMapping对业务模块区分。 StudentController。 TeacherController。 &#xff08;2&#xff09;Apifox请求与响应。 "/student/login"。 "/teacher/login"。 二、常见参数…

回溯算法+对称剪枝——从八皇后问题到数独问题(二)

引入&#xff1a; 本节我们进一步完善八皇后问题&#xff0c;学习剪枝、八皇后残局问题 进一步领会逻辑编程的概念&#xff0c;深入体会回溯算法&#xff0c;回顾上一节提到的启发搜索策略。 回顾&#xff1a; 八皇后问题&#xff1a;我们需要在一个空棋盘上放置 n 个皇后&a…

【玩泰山派】MISC(杂项)- 使用vscode远程连接泰山派进行开发

文章目录 前言流程1、安装、启动sshd2、配置一下允许root登录3、vscode中配置1、安装remote插件2、登录 **注意** 前言 有时候要在开发板中写一写代码&#xff0c;直接在终端中使用vim这种工具有时候也不是很方便。这里准备使用vscode去通过ssh远程连接泰山派去操作&#xff0…

【VsCode】设置文件自动保存

目录 一、前言 二、操作步骤 一、前言 VSCode中开启自动保存功能可以通过访问设置、修改settings.json文件、使用自动保存延迟功能来实现。这些方法能有效提升编程效率、避免数据丢失、实时同步更改。 二、操作步骤 在 Visual Studio Code (VS Code) 中设置自动保存功能非…