聊聊抽象SQL那些事儿,顺带说说参数化查询怎么用才靠谱
- 问答
- 2026-01-11 00:16:55
- 1
知乎专栏《数据库实战笔记》)
聊聊抽象SQL那些事儿,顺带说说参数化查询怎么用才靠谱
咱们先来说说“抽象SQL”这个概念,你可能听过别人说“不要把SQL语句写死”,这个“写死”的反面,某种程度上就是“抽象”。(内容来源:Stack Overflow 某高赞回答关于动态SQL的讨论)举个例子,假如你要查一个用户表,最开始的需求是查名字叫“张三”的人,你可能会写:
SELECT * FROM users WHERE name = '张三';
这没问题,但过两天产品经理说,我还要能按年龄查、按城市查,这时候,如果你为每个条件都写一条单独的SQL,代码会变得又长又臭,难以维护,这种时候,就需要“抽象”一下了,抽象的核心思想是,把变化的部分和不变的部分分开。
一种常见的做法是动态拼接SQL字符串,根据前端传过来的条件,在代码里像拼积木一样把WHERE子句拼起来,如果用户只选了名字,就拼上name = '某某';如果又选了年龄,就再加一个AND age = 25。
来源:经典编程书籍《代码大全》)这种方法听起来灵活,但一不小心就会掉进一个大坑:SQL注入攻击,想象一下,如果用户在心怀叵测,在名字那个输入框里不是输入“张三”,而是输入 ' OR '1'='1,你拼接出来的SQL就变成了:

SELECT * FROM users WHERE name = '' OR '1'='1';
这下可好,'1'='1'这个条件永远为真,你的查询就把整个用户表的数据都泄露了!这简直就是给黑客开了后门,正是因为这种字符串拼接的方式太危险,我们才需要请出今天的主角——参数化查询。
参数化查询,说白了,就是一种“安全快递”的方式,你把SQL语句本身(比如SELECT * FROM users WHERE name = ?)和要传递的参数(张三”)分开打包,交给数据库,数据库会非常明确地知道:“哦,问号这里是一个参数值,它的内容是‘张三’,我只把它当作纯粹的数据来用,绝不会把它当成可以执行的SQL指令。”
来源:微软MSDN官方文档关于SqlParameter的说明)这样,即使用户输入了' OR '1'='1,数据库也会老老实实地去寻找名字叫' OR '1'='1的这个奇怪用户,当然肯定找不到,但绝不会引发安全问题,这就从根源上杜绝了SQL注入。

参数化查询怎么用才靠谱呢?我觉得有几点特别重要:
第一,无脑用, everywhere,只要你的查询里有来自用户输入、外部接口或者任何不可信来源的数据,就必须用参数化查询,不要有任何侥幸心理,觉得“这个输入框只有内部人员用,没关系”,安全漏洞往往就出现在你最意想不到的地方。
第二,认清参数的真面目,参数化查询只能保护“值”,不能保护“SQL关键字或者表名、列名”。(内容来源:一位资深DBA的博客警示)比如说,你不能用参数来代替ORDER BY后面的列名,如果你想让用户选择按年龄还是按姓名排序,代码应该是判断用户选择,然后在一个预定义的安全选项集合里(比如"age"或"name")进行选择,再安全地拼接进SQL语句,而不是直接把用户输入当成列名用参数传进去,对于表名也是同样的道理,这部分动态内容,必须通过白名单(只允许特定的几个值)的方式来控制,确保它是安全的。
第三,别忘了参数的类型,给参数赋值的时候,最好明确指定它的数据类型,比如是整数、字符串还是日期,不要让数据库去猜,明确类型能让数据库更高效地执行查询,有时候还能避免一些因类型隐式转换导致的性能问题或意想不到的错误。
抽象SQL是为了让代码更灵活、更易维护,但在这个过程中,我们必须牢牢握住“安全”这根缰绳,参数化查询就是我们最可靠的安全带,它简单、有效,是每个开发者都必须掌握和习惯使用的编程实践,别再拼接字符串了,从现在开始,养成使用参数化查询的好习惯,让你的应用更坚固。
本文由革姣丽于2026-01-11发表在笙亿网络策划,如有疑问,请联系我们。
本文链接:https://www.haoid.cn/wenda/78368.html