【问题标题】:Couple of questions on Prepared Statements [duplicate]关于准备好的陈述的几个问题[重复]
【发布时间】:2025-12-10 10:50:02
【问题描述】:

可能重复:
why MySQLi prepared statements?

所以我有几个关于准备好的陈述的问题。

第一个是,我的朋友告诉我,它们比传统的“Select from * users where sID = '$id';”更安全,因为数据库采用不同的输入并且知道它是一个值而不是一个整体查询所以;'没有结束查询。

其次,如果使用prepared statements,是否还需要对值进行转义?

第三,准备好的语句对性能/可靠性有很大影响吗?

【问题讨论】:

标签: php mysql mysqli prepared-statement


【解决方案1】:

转义查询对于区分命令是必要的:

SELECT * FROM foo WHERE name = 'O'Connor'

解析器不容易理解“O'Connor”中的'属于,它会将其视为终止字符串。转义有助于解析器区分:

SELECT * FROM foo WHERE name = 'O\'Connor'

准备好的语句分两步发送到数据库:首先是命令,然后是

command: SELECT * FROM foo WHERE name = ?
value:   O'Connor

这对解析器来说是明确的。因此,您不需要转义该值,因为您需要转义该值的唯一原因不再适用。这也是它更安全的原因,因为您永远无法逃避该值并祈祷 SQL 注入。

至于速度,单个查询应该不会有太大变化。如果您重用同一准备好的查询多次使用不同的值,这将有助于提高性能,因为数据库不需要一次又一次地解析整个查询。

如需更深入介绍:The Great Escapism (Or: What You Need To Know To Work With Text Within Text)

【讨论】:

    【解决方案2】:
    1. 准备好的 SQL 可防止 SQL 注入发生,并使代码更具可读性。
    2. 因为他们已经准备好了,所以他们不需要你准备。所以,不,他们不需要转义
    3. 这些将像任何其他 TSQL 语句一样运行。如果你想提高性能,那么你应该考虑使用存储过程,因为它们是“预编译的”

    【讨论】:

    • 我认为 3 并不完全准确。是否缓存常用语句由实现决定。
    • 是的,这就是我让它保持打开状态的原因,只是说它会像任何其他 TSQL 语句一样运行。如果引擎再次得到相同的查询,那么它将命中缓存,否则不会。
    • 正确。尽管对此的细微差别是,如果您使用标准字符串,除非收到完全相同的查询,否则它不会命中 chache。但是,使用PS,如果参数发生变化,仍然会被识别
    【解决方案3】:
    1. 将用户输入直接插入 SQL 语句是一个巨大的安全漏洞。它被称为SQL injection。使用准备好的语句将弥补这个漏洞。
    2. 如果您使用绑定,您不必自己转义这些值。使用预准备语句涉及使用绑定,但您可以在不使用预准备语句的情况下使用绑定。
    3. 如果重复使用准备好的语句可以提高性能。对于一次性使用,它们没有太大区别。

    【讨论】:

      【解决方案4】:

      首先,是的,准备好的语句,如参数化语句,在处理参数时更加安全

      这是因为参数与查询本身分开。如果您想知道只传递如下查询有什么问题:

      select * from tbl where name = '$username'
      

      只需在网上搜索“Little Bobby Tables”:-) 或“SQL 注入”。

      其次,您不必转义准备好的语句的值,因为 SQL 注入的危险已消除(请参阅前一点)。

      第三,一般不会。性能归结为针对数据库运行的查询,这在常规 SQL 和准备好的语句之间可能不会有太大变化。

      【讨论】:

        【解决方案5】:

        准备好的语句是预编译的,因此查询的结构是安全的,不会被篡改。然后将参数绑定到语句并执行。如果您正在执行相同的查询 - 只是使用不同的参数 - 多次准备好的语句实际上是一个巨大的性能提升。如果您使用准备好的语句,则不需要转义这些值。简而言之,准备好的语句很棒!

        【讨论】: