总结:
参数化不是为了复用查询结果,
而是为了固定 SQL 结构,让解析和执行行为可预测;
同时通过语义隔离彻底消除 SQL 注入。
字符串拼接:
varids=string.Join(",",idList);varsql=$@" SELECT * FROM a WHERE a.id IN ({ids}); ";//生成sql可能是SELECT*FROM a WHEREa.idIN(1,2,3,4,5,6,7,8,9,...);参数化sql:
varparameters=newList<MySqlParameter>();varplaceholders=newList<string>();for(inti=0;i<idList.Count;i++){varname=$"@id{i}";placeholders.Add(name);parameters.Add(newMySqlParameter(name,idList[i]));}varsql=$@" SELECT * FROM a WHERE a.id IN ({string.Join(",",placeholders)}); ";//生成固态sqlSELECT*FROM a WHEREa.idIN(@id0,@id1,@id2,...);在代码层面,虽然每次调用都是不同的sql,但是对于mysql数据库来说完全不一样。
上面给出的两个代码注释下面就是数据库接收到的sql模式,可以看到,参数化每次数据库接收的都是一样的。因此参数化让数据库能够 复用 解析结构和执行计划,从而减少解析与优化的开销。而拼接字符串每次都是不同的sql语句,需要重新解析。
另外拼接字符串会有注入的风险,但是参数化不会有。因为数据库在解析阶段只确认“占位符的位置和类型”,并不会把参数值当成 SQL 语法来解析。
举个例子说明:
这是字符串拼接
sql="WHERE id IN ("+userInput+")";//如果用户输入1)OR1=1--//最终sql是WHEREidIN(1)OR1=1--)参数化
WHEREidIN(?)//输入1)OR1=1--//数据库看到id="1) OR 1=1 --"数据库处理流程是:
1.先解析 SQL 结构
2.确认:? 是一个“值占位符”
3.SQL 语法树已经固定
4.再把参数值“绑定”为数据
完结撒花~