【问题标题】:PreparedStatement.setString() method without quotes [duplicate]不带引号的 PreparedStatement.setString() 方法[重复]
【发布时间】:2011-02-24 10:33:57
【问题描述】:

我正在尝试使用带有类似代码的 PreparedStatement:

SELECT * FROM ? WHERE name = ?

显然,当我使用 setString() 设置表和名称字段时会发生什么:

SELECT * FROM 'my_table' WHERE name = 'whatever'

并且查询不起作用。有没有办法设置不带引号的字符串,所以该行如下所示:

SELECT * FROM my_table WHERE name = 'whatever'

或者我应该放弃它并改用常规语句(参数来自系统的另一部分,用户都没有输入)?

【问题讨论】:

  • 您正在考虑这样做的事实向我表明,您应该考虑重塑您的数据。也许您应该创建一个合并所有表的视图,并添加一个作为“表名”的列。

标签: java sql jdbc prepared-statement


【解决方案1】:

您犯的错误是您无法将表名作为参数传递。您应该只将值传递给 SQL 语句。

例如: 如果你想:

Select * from LoggedUsers where username='whatever' and privilege='whatever';

那么您必须将 PreparedStatement 构建为:

Select * from LoggedUsers where username=? and privilege=?

setString(1, usernameObject);
setString(2, privilegeObject);

PreparedStatement 的目的是降低数据库连接代码的难度和可读性。 当开发人员必须在 Statement 的实例中使用如此多的列值时,很难放置分号、逗号和加号(连接运算符)。

我认为您错误地想利用它,这不是设计为......

【讨论】:

  • 这个答案的后半部分是完全错误的。准备好的语句是为了安全(即防止注入),而不是为了可读性。
【解决方案2】:

我怀疑您的 SQL 是否真的以这种方式无限灵活。您只有有限数量的表,因此用于表达所需 SQL 的静态最终字符串的数量也是有限的。

继续使用 PreparedStatement 并绑定您的变量。这是完全值得的,在避免 SQL 注入问题时特别有用。

【讨论】:

  • 您显然没有阅读足够的 TheDailywtf.com。每个客户都有一张桌子(并且客户数量不受限制)是一种使用过的反模式。
  • 显然不是。感谢您的提醒。 8)
【解决方案3】:

参数不能用于参数化表,或参数化任何数据库对象。它们主要用于参数化 WHERE/HAVING 子句。

要做你想做的事,你需要自己做替换,并根据需要创建一个常规语句。

当您使用准备好的语句时,这是一个提示数据库对语句进行预先处理 - 例如解析字符串并可能确定执行计划。如果查询中使用的对象可以动态变化,那么数据库就无法做太多的前期准备。

【讨论】:

  • 更进一步,使用 setString 并不是在字符串周围加上引号,因为它没有(绑定变量不能那样工作)。只是你不能在查询的那部分使用变量。
  • 知道了,谢谢!你会说使用 PreparedStatement 在这里没有多大意义,因为参数不是用户输入的吗?我的意思是它可能比使用常规语句更昂贵。还是无论如何我都应该在任何地方使用 PreparedStatement?
  • 您仍然可以使用 PreparedStatement,只是不要尝试参数化表名 - 参数化“谁”。关于使用准备好的陈述与常规陈述存在一些争论,但我认为共识是使用准备好的陈述,除非你发现有充分的理由不这样做。
【解决方案4】:

不幸的是,您不能为准备好的语句参数化表名。如果需要,您可以构造一个字符串并将其作为动态 SQL 执行。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-12-27
    • 2021-11-08
    • 1970-01-01
    • 2013-08-16
    • 1970-01-01
    • 2020-07-29
    • 2013-11-29
    相关资源
    最近更新 更多