参数化查询
✍ dations ◷ 2025-08-26 05:36:34 #数据库,网络安全,SQL
参数化查询(parameterized query 或 parameterized statement)是指在设计与数据库链接并访问资料时,在需要填入数值或资料的地方,使用参数(parameter)来给值,这个方法目前已被视为最有效可预防SQL注入攻击的攻击手法的防御方式。
除了安全因素,相比起拼接字符串的SQL语句,参数化的查询往往有性能优势。因为参数化的查询能令不同的数据通过参数到达数据库,从而共享同一条SQL语句。大多数数据库会缓存解释SQL语句产生的字节码而省下重复解析的开销。如果采取拼接字符串的SQL语句,则会由于操作数据是SQL语句的一部分而非参数的一部分,而反复大量解释SQL语句产生不必要的开销。
在使用参数化查询的情况下,数据库服务器不会将参数的内容视为SQL指令的一部分来处理,而是在数据库完成SQL指令的编译后,才套用参数运行,因此就算参数中含有具破坏性的指令,也不会被数据库所运行。
在撰写SQL指令时,利用参数来代表需要填入的数值,例如:
Microsoft SQL Server的参数格式是以"@"字符加上参数名称而成,SQL Server亦支持匿名参数"?"。
SELECT * FROM myTable WHERE myID = @myID
INSERT INTO myTable (c1, c2, c3, c4) VALUES (@c1, @c2, @c3, @c4)
Microsoft Access
Microsoft Access不支持具名参数,只支持匿名参数"?"。
UPDATE myTable SET c1 = ?, c2 = ?, c3 = ? WHERE c4 = ?
MySQL
MySQL的参数格式是以"@"字符加上参数名称而成。
set @c1 := xxx;set @c2 := xxx; set @c3 := xxx;set @c4 := xxx;UPDATE myTable SET c1 = @c1, c2 = @c2, c3 = @c3 WHERE c4 = @c4
PostgreSQL/SQLite
PostgreSQL和SQLite的参数格式是以“:”加上参数名而成。当然,也支持类似Access的匿名参数。
UPDATE "myTable" SET "c1" = :c1, "c2" = :c2, "c3" = :c3 WHERE "c4" = :c4
客户端程序撰写方法
在客户端代码中撰写使用参数的代码,例如:
ADO.NET用于ASP.NET之内。
SqlCommand sqlcmd = new SqlCommand("INSERT INTO myTable (c1, c2, c3, c4) VALUES (@c1, @c2, @c3, @c4)", sqlconn);sqlcmd.Parameters.AddWithValue("@c1", 1); // 設定參數@c1的值。sqlcmd.Parameters.AddWithValue("@c2", 2); // 設定參數@c2的值。sqlcmd.Parameters.AddWithValue("@c3", 3); // 設定參數@c3的值。sqlcmd.Parameters.AddWithValue("@c4", 4); // 設定參數@c4的值。sqlconn.Open();sqlcmd.ExecuteNonQuery();sqlconn.Close();
PDO
PDO用于PHP之内。在使用PDO驱动时,参数查询的使用方法一般为:
// 实例化数据抽象层对象$db = new PDO('pgsql:host=127.0.0.1;port=5432;dbname=testdb');// 对SQL语句执行prepare,得到PDOStatement对象$stmt = $db->prepare('SELECT * FROM "myTable" WHERE "id" = :id AND "is_valid" = :is_valid');// 绑定参数$stmt->bindValue(':id', $id);$stmt->bindValue(':is_valid', true);// 查询$stmt->execute();// 获取数据foreach($stmt as $row) { var_dump($row);}
对于MySQL的特定驱动,也可以这样使用:
$db = new mysqli("localhost", "user", "pass", "database");$stmt = $db -> prepare("SELECT priv FROM testUsers WHERE username=? AND password=?");$stmt -> bind_param("ss", $user, $pass);$stmt -> execute();
值得注意的是,以下方式虽然能有效防止SQL注入(归功于mysql_real_escape_string函数的转义),但并不是真正的参数化查询。其本质仍然是拼接字符串的SQL语句。
$query = sprintf("SELECT * FROM Users where UserName='%s' and Password='%s'", mysql_real_escape_string($Username), mysql_real_escape_string($Password));mysql_query($query);
ODBC/JDBC
ODBC 使用 C 样式的函数 / 句柄接口,而 JDBC 用于 Java 之内。
相关
- 十七省十七省是15世纪到16世纪时,哈布斯堡尼德兰帝国政治体的术语。十七省大致包含低地国,也就是目前荷兰、比利时和卢森堡;同时再加上大部分现代法国北部省,包括亚多亚、法国佛兰德斯
- 甘油磷脂甘油磷脂(Phosphoglyceride或Glycerophospholipid)是由甘油构成的磷脂,其分子结构中甘油的1号和2号位羟基均被脂酰基取代,3号位羟基则为含磷基团所取代。是一种两性分子。它们是
- 诺特定理诺特定理是理论物理的中心结果之一,它表达了连续对称性和守恒定律的一一对应。例如,物理定律不随着时间而改变,这表示它们有关于时间的某种对称性。举例来说,若现实中重力的强度
- 让-巴普蒂斯·贝西埃尔让-巴普蒂斯·贝西埃尔(Jean Baptiste Bessières,1768年8月6日-1813年5月1日),法国军人、拿破仑麾下的元帅、帝国近卫军司令,获封伊斯特利亚公爵。贝西埃尔出生于法国南部卡赫尔
- 淮夷淮夷,可能是存在于中国上古时代的夏至东周时期,生活在中国东部的黄淮、江淮一带的东夷部族统称。根据《竹书纪年》记载,夏朝的相在即位的第一年,进攻淮夷,第二年攻风夷、黄夷,第七
- 兰兰山兰兰山(Mount Lamlam,Lamlam为查莫罗语中闪电之意),或按上述直译为闪电山,位于美国关岛西南部,位于阿加特(英语:Agat, Guam)北方5千米或3英里。
- 皮特·肖内西彼得·安东尼·肖内西(Peter Anthony "Pete" Shaughnessy,1962年9月16日 - 2002年12月15日)是英格兰心理健康活动家、疯子尊严运动的创始人之一。皮特生于南伦敦,当过公交司机,19
- 室生犀星室生犀星(日语:室生 犀星、1889年8月1日-1962年3月26日),本名:室生照道,是日本诗人、小说家,别号为“鱼眠洞”。“室生”的平假名通常写作“むろう ”,不过室生犀星本人则“むろう”
- 霍华德·斯科特·华沙霍华德·斯科特·华沙(Howard Scott Warshaw,1957年7月30日-)是美国心理治疗师,前电子游戏设计师、程序员。他在1980年代为雅达利游戏机雅达利2600创作了《亚尔复仇记》、《夺宝
- 朝潮太郎 (3代)第三代朝潮太郎(1929年11月13日-1988年10月23日),本名米川文敏,身高1.88米,重135公斤,日本鹿儿岛县德之岛出身(出生地兵库县神户市)的大相扑力士,第46代横纲,高砂部屋所属。1948年10月,