在“WHERE column =?”中MySQL中问号的意义是什么?

我正在解剖一些代码,碰到这个,

$sql = 'SELECT page.*, author.name AS author, updator.name AS updator ' . 'FROM '.TABLE_PREFIX.'page AS page ' . 'LEFT JOIN '.TABLE_PREFIX.'user AS author ON author.id = page.created_by_id ' . 'LEFT JOIN '.TABLE_PREFIX.'user AS updator ON updator.id = page.updated_by_id ' . 'WHERE slug = ? AND parent_id = ? AND (status_id='.Page::STATUS_REVIEWED.' OR status_id='.Page::STATUS_PUBLISHED.' OR status_id='.Page::STATUS_HIDDEN.')'; 

我在想什么“?” 在WHERE语句中。 它是某种参数持有者吗?

编写的语句使用“?” 在MySQL中允许绑定参数的声明。 高度重视,如果使用得当,更安全的SQL注入。 这也允许更快的SQL查询,因为请求只需编译一次即可重用。

问号表示稍后将被replace的参数。 使用参数化查询比将参数直接embedded查询更安全。

SQL Server调用这个参数化查询,而Oracle调用它绑定variables。

用法因您执行查询的语言而异。

这里是一个如何使用PHP的例子。

假设$mysqli是一个数据库连接,而people是一个有4列的表。

 $stmt = $mysqli->prepare("INSERT INTO People VALUES (?, ?, ?, ?)"); $stmt->bind_param('sssd', $firstName, $lastName, $email, $age); 

'sssd'是标识其余参数的标志,其中s代表string, d代表数字。

没有

? 对MySQL的WHERE =子句没有任何意义,只对几个外部接口如PHP stdlib和像Rails这样的Web框架有效。

? 只是一个语法错误:

 CREATE TABLE t (s CHAR(1)); SELECT * FROM t WHERE s = ?; 

因为它没有被引用,并且在:

 INSERT INTO t VALUES ('a'); INSERT INTO t VALUES ("?"); SELECT * FROM t WHERE s = '?'; 

它返回:

 s ? 

因此显然没有特别的意义。

Rails的例子

例如,在Rails中,问号由库的编程语言(Ruby)的variables给出的参数代替,例如:

 Table.where("column = ?", "value") 

并自动引用参数以避免错误和SQL注入,生成一个像这样的语句:

 SELECT * FROM Table WHERE column = 'value'; 

引用可以拯救我们,例如:

 Table.where("column = ?", "; INJECTION") 

MySQL 5.0准备好的语句

MySQL 5.0在web框架中添加了与问号具有相似语义的预编译语句function 。

来自文档的示例:

 PREPARE stmt1 FROM 'SELECT SQRT(POW(?,2) + POW(?,2)) AS hypotenuse'; SET @a = 3; SET @b = 4; EXECUTE stmt1 USING @a, @b; 

输出:

 hypotenuse 5 

如预期的那样,

 PREPARE stmt1 FROM 'SELECT ? AS s'; SET @a = "'"; EXECUTE stmt1 USING @a; 

输出:

 s ' 

这些是准备好的陈述,准备好的陈述提供了两大好处:

查询只需要parsing(或准备)一次,但可以用相同或不同的参数多次执行。 查询准备好后,数据库将分析,编译和优化执行查询的计划。 对于复杂的查询,如果需要用不同的参数多次重复相同的查询,那么这个过程会花费足够的时间,以至于会明显地减慢应用程序的速度。 通过使用准备好的语句,应用程序避免重复分析/编译/优化循环。 这意味着准备好的语句使用更less的资源,从而运行得更快。

准备报表的参数不需要引用; 驱动程序自动处理这个。 如果一个应用程序独占地使用了准备好的语句,那么开发人员可以确保不会发生SQL注入(但是,如果查询的其他部分正在使用非转义input构build,则SQL注入仍然是可能的)。

http://php.net/manual/en/pdo.prepared-statements.php