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. 安全实践
- 禁止用户控制表名:表名应在代码层生成(如根据时间分表),而非直接传递用户输入。
- 白名单校验:若必须动态传参,需校验参数格式(如正则匹配
^[a-zA-Z0-9_]+$)。 - 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=users, 2=products),后端映射为真实表名。 - 参数加密:用户传入加密参数,后端解密后匹配预定义表名。
- 数据库权限隔离:动态表操作使用只读低权限账号。
场景:
高级岗位考察系统设计能力,尤其是安全与灵活性平衡的方案。
六、总结与最佳实践
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 协议文档深入理解。
相关文章:
MySQL 中 `${}` 和 `#{}` 占位符详解及面试高频考点
文章目录 一、概述二、#{} 和 ${} 的核心区别1. 底层机制代码示例 2. 核心区别总结 三、为什么表名只能用 ${}?1. 预编译机制的限制2. 动态表名的实现 四、安全性注意事项1. ${} 的风险场景2. 安全实践 五、面试高频考点1. 基础原理类问题**问题 1**:**问…...
AI应用开发平台 和 通用自动化工作流工具 的详细对比,涵盖定义、核心功能、典型工具、适用场景及优缺点分析
以下是 AI应用开发平台 和 通用自动化工作流工具 的详细对比,涵盖定义、核心功能、典型工具、适用场景及优缺点分析: 1. AI应用开发平台 vs 通用自动化工作流工具 (1) 定义与目标 类型AI应用开发平台通用自动化工作流工具定义用于快速构建、训练、部署…...
GitHub 趋势日报 (2025年04月12日)
本日报由 TrendForge 系统生成 https://trendforge.devlive.org/ 📈 今日整体趋势 Top 10 排名项目名称项目描述今日获星总星数语言1yeongpin/cursor-free-vip[Support 0.48.x](Reset Cursor AI MachineID & Auto Sign Up / In & Bypass Higher…...
asm汇编源代码之-字库转换程序
将标准的16x16点阵汉字库(下载16x16汉字库)转换成适合VGA文本模式下显示的点阵汉字库 本程序需要调用file.asm中的子程序,所以连接时需要把file连接进来,如下 C:\> tlink chghzk file 调用参数描述如下 C:\> chghzk ; 无调用参数,转换标准库文件(SRC16.FNT)为适合VGA…...
VMware Ubuntu挂载Windows机器的共享文件
https://www.dong-blog.fun/post/2029 在VMware Ubuntu中访问Windows共享文件夹:完整指南 在使用VMware运行Ubuntu虚拟机时,访问Windows主机上的文件是常见需求。本文将详细介绍如何通过网络共享方式,让Ubuntu虚拟机直接访问Windows主机的文…...
智慧社区数据可视化中枢平台——Axure全场景交互式大屏解决方案
在数字化治理的时代浪潮中,社区管理正面临数据碎片化、响应滞后、决策盲区等核心挑战。如何将分散的安防、环境、能源、民生服务等数据整合为可操作的智慧洞察?如何让冰冷的数字转化为社区管理者手中的决策利器?Axure智慧社区可视化大屏原型模…...
Axure高保真AI算法训练平台
点击下载《Axure高保真AI算法训练平台(.rp) 》 原型效果:https://axhub.im/ax9/69fdf8f2b10b59c3/#g1 摘要 本文介绍了一款功能全面且高效的AI算法训练平台,旨在为数据科学家、研究人员和工程师提供从数据准备到模型部署的一站式解决方案。该平台由四大…...
C++ Json-Rpc框架-3项目实现(2)
一.消息分发Dispatcher实现 Dispatcher 就是“消息分发中枢”:根据消息类型 MType,把消息派发给对应的处理函数(Handler)执行。 初版: #pragma once #include "net.hpp" #include "message.hpp"n…...
youtube视频和telegram视频加载原理差异分析
1. 客户侧缓存与流式播放机制 流式视频应用(如 Netflix、YouTube)通过边下载边播放实现流畅体验,其核心依赖以下技术: 缓存预加载:客户端在后台持续下载视频片段(如 DASH/HLS 协议的…...
LLM小白自学笔记:1.两种指令微调
一、LoRA 简单来说,LoRA不直接调整个大模型的全部参数(那样太费资源),而是在模型的某些层(通常是注意力层)加个“旁路”——两个小的矩阵(低秩矩阵)。训练时只更新这俩小矩阵&#x…...
【NLP】 19. Tokenlisation 分词 BPE, WordPiece, Unigram/SentencePiece
1. 翻译系统性能评价方法 在机器翻译系统性能评估中,通常既有人工评价也有自动评价方法: 1.1 人工评价 人工评价主要关注以下几点: 流利度(Fluency): 判断翻译结果是否符合目标语言的语法和习惯。充分性…...
OpenAI发布GPT-4.1系列模型——开发者可免费使用
OpenAI刚刚推出GPT-4.1模型家族,包含GPT-4.1、GPT-4.1 Mini和GPT-4.1 Nano三款模型。重点是——现在全部免费开放! 虽然技术升级值得关注,但真正具有变革意义的是开发者能通过Cursor、Windsurf和GitHub Copilot等平台立即免费调用这些模型。…...
各地物价和生活成本 东欧篇
东欧地区的物价差异相对较大,一些国家的物价较高,而另一些国家则相对便宜。这些差异主要受当地经济发展水平、工资水平、旅游业发展以及国际关系等因素影响。以下是一些典型的东欧国家,按物价高低进行分类: 🌍 物价较高…...
Vue —— 实用的工具函数
目录 响应式数据管理1. toRef 和 torefs2. shallowRef 和 shallowReactive3. markRaw 依赖追踪与副作用1. computed2. watch 和 watchEffect 类型判断与优化1. unref2. isRef 、isReactive 和 isProxy 组件通信与生命周期1. provide 和 inject2. nextTick 高级工具1. useAttrs …...
flex布局(笔记)
弹性布局(Flex布局)是一种现代的CSS布局方式,通过使用display: flex属性来创建一个弹性容器,并在其中使用灵活的盒子模型来进行元素的排列和定位。 主轴与交叉轴:弹性容器具有主轴(main axis)和…...
第二阶段:数据结构与函数
模块4:常用数据结构 (Organizing Lots of Data) 在前面的模块中,我们学习了如何使用变量来存储单个数据,比如一个数字、一个名字或一个布尔值。但很多时候,我们需要处理一组相关的数据,比如班级里所有学生的名字、一本…...
云函数采集架构:Serverless模式下的动态IP与冷启动优化
在 Serverless 架构中使用云函数进行网页数据采集,不仅能大幅降低运维成本,还能根据任务负载动态扩展。然而,由于云函数的无状态特性及冷启动问题,加上目标网站对采集行为的反制措施(如 IP 限制、Cookie 校验等&#x…...
Linux笔记---动静态库(原理篇)
1. ELF文件格式 动静态库文件的构成是什么样的呢?或者说二者的内容是什么? 实际上,可执行文件,目标文件,静态库文件,动态库文件都是使用ELF文件格式进行组织的。 ELF(Executable and Linkable…...
string的模拟实现 (6)
目录 1.string.h 2.string.cpp 3.test.cpp 4.一些注意点 本篇博客就学习下如何模拟实现简易版的string类,学好string类后面学习其他容器也会更轻松些。 代码实现如下: 1.string.h #define _CRT_SECURE_NO_WARNINGS 1 #pragma once #include <…...
【野火模型】利用深度神经网络替代 ELMv1 野火参数化:机制、实现与性能评估
目录 一、ELMv1 野火过程表示法(BASE-Fire)关键机制野火模拟的核心过程 二、采用神经网络模拟野火过程三、总结参考 一、ELMv1 野火过程表示法(BASE-Fire) ELMv1 中的野火模型(称为 BASE-Fire)源自 Commun…...
红宝书第四十七讲:Node.js服务器框架解析:Express vs Koa 完全指南
红宝书第四十七讲:Node.js服务器框架解析:Express vs Koa 完全指南 资料取自《JavaScript高级程序设计(第5版)》。 查看总目录:红宝书学习大纲 一、框架定位:HTTP服务器的工具箱 共同功能: 快…...
嵌入式Linux设备使用Go语言快速构建Web服务,实现设备参数配置管理方案探究
本文探讨,利用Go语言及gin框架在嵌入式Linux设备上高效搭建Web服务器,以实现设备参数的网页配置。通过gin框架,我们可以在几分钟内创建一个功能完善的管理界面,方便对诸如集中器,集线器等没有界面的嵌入式设备的管理。…...
【NLP 59、大模型应用 —— 字节对编码 bpe 算法】
目录 一、词表的构造问题 二、bpe(byte pair encoding) 压缩算法 算法步骤 示例: 步骤 1:初始化符号表和频率统计 步骤 2:统计相邻符号对的频率 步骤 3:合并最高频的符号对 步骤 4:重复合并直至终止条件 三、bpe在NLP中…...
Python对ppt进行文本替换、插入图片、生成表格
目录 1. 安装pptx2. 文本替换和插入图片3. 生成表格 1. 安装pptx pip install python-pptx2. 文本替换和插入图片 文本通过占位符例如{{$xxx}}进行标记,然后进行替换;图片通过ppt中的图形和图片中的占位符进行标记ppt如下 具体实现 from pptx import …...
AI(学习笔记第一课) 在vscode中配置continue
文章目录 AI(学习笔记第一课) 在vscode中配置continue学习内容:1. 使用背景2. 在vscode中配置continue2.1 vscode版本2.2 在vscode中下载continue插件2.2.1 直接进行安装2.2.2 在左下角就会有continue的按钮2.2.3 可以移动到右上角2.2.3 使用的时候需要login 2.3 配…...
C++ (初始面向对象之继承,实现继承,组合,修饰权限)
初始面向对象之继承 根据面向对象的编程思路,我们可以把共性抽象出来封装成类,然后让不同的角色去继承这些类,从而避免大量重复代码的编写 实现继承 继承机制是面向对象程序设计中使代码可以复用的最重要的手段,它允许程序员在保…...
vmcore分析锁问题实例(x86-64)
问题描述:系统出现panic,dmesg有如下打印: [122061.197311] task:irq/181-ice-enp state:D stack:0 pid:3134 ppid:2 flags:0x00004000 [122061.197315] Call Trace: [122061.197317] <TASK> [122061.197318] __schedule0…...
21、c#中“?”的用途
在C#中,? 是一个多用途的符号,具有多种不同的用途,具体取决于上下文。以下是一些常见的用法: 1、可空类型(Nullable Types) ? 可以用于将值类型(如 int、bool 等)变为可空类型。…...
每日搜索--12月
12.1 1. urlencode是一种编码方式,用于将字符串以URL编码的形式进行转换。 urlencode也称为百分号编码(Percent-encoding),是特定上下文的统一资源定位符(URL)的编码机制。它适用于统一资源标识符(URI)的编码,也用于为application/x-www-form-urlencoded MIME准备数…...
一天一个java知识点----Tomcat与Servlet
认识BS架构 静态资源:服务器上存储的不会改变的数据,通常不会根据用户的请求而变化。比如:HTML、CSS、JS、图片、视频等(负责页面展示) 动态资源:服务器端根据用户请求和其他数据动态生成的,内容可能会在每次请求时都…...
