直接拼接SQL字符串会触发SQL注入,因为用户输入被当作SQL代码执行而非数据;参数化查询通过预编译分离结构与数据,强制输入仅为值,需同时满足声明占位符、设类型、赋Value值三条件才生效。

为什么直接拼接SQL字符串会触发SQL注入
Delphi里用 TADOQuery 时,如果写成 ADOQuery1.SQL.Text := 'SELECT * FROM users WHERE name = ''' + Edit1.Text + '''';,攻击者输入 O'Reilly'; DROP TABLE users; -- 就能执行任意语句。根本原因是字符串拼接把用户输入当成了SQL代码的一部分,数据库引擎不区分“数据”和“指令”。
参数化查询强制把输入当作纯数据处理,数据库预编译时就固定了语句结构,后续只填充值,不会重新解析语法。
正确使用Parameters对象的三步操作
必须同时满足三个条件才真正生效:声明参数占位符、设置参数类型、赋值。漏掉任一环都可能退化为拼接行为或报错。
- SQL文本中用
:开头命名参数(如WHERE name = :user_name),不能用@或? - 调用
Parameters.ParamByName('user_name').DataType := ftString;显式指定类型,避免隐式转换失败 - 赋值必须用
.Value属性(Parameters.ParamByName('user_name').Value := Edit1.Text;),不能用.AsString等子属性——后者在参数未初始化时会触发访问异常
ftWideString 和 ftString 的实际区别在哪
Delphi 2009+ 默认使用 Unicode 字符串,但 SQL Server 的 varchar 列对应 ftString,nvarchar 才对应 ftWideString。混用会导致乱码或截断,尤其处理中文时。
常见错误是全部用 ftString,结果 SQL Server 把传入的 Unicode 字符按单字节截断;或者全用 ftWideString,连接旧版 Access 数据库时报“类型不匹配”。
- 查
varchar/char字段 → 用ftString - 查
nvarchar/nchar字段 → 用ftWideString - 不确定时,先用
ADOConnection.GetFieldNames查表结构确认字段类型
动态SQL中参数名重复或缺失的典型报错
运行时报 Parameter 'xxx' not found,大概率是 SQL 文本里写了 :user_id,但代码里调用了 ParamByName('userid')(少下划线);或者 SQL 里参数名大小写不一致(虽然 ADO 通常不敏感,但某些驱动版本会校验)。
更隐蔽的问题是循环中反复调用 Parameters.Clear 后没重设类型,导致第二次执行时参数类型丢失,数值类参数(如 ftInteger)传入空字符串会抛出类型转换异常。
- 参数名严格保持大小写和拼写一致,建议全小写加下划线
- 避免在循环里调用
Clear,改用ParamByName('x').Value := newValue覆盖赋值 - 调试时用
ADOQuery1.Parameters.Count和Parameters[i].Name检查实际加载的参数列表
参数绑定不是加个冒号就完事,关键在类型匹配和生命周期管理。最容易被忽略的是:SQL Server 连接字符串里 Provider=SQLOLEDB 时默认禁用 Unicode 参数,必须显式加 UseUnicode=True,否则 ftWideString 仍会降级为 ANSI。

















