传递表名作为预处理语句的参数

我正在尝试学习如何在Java中使用MySQL,正如标题所说,我在准备语句时遇到问题。

我有一个名为temp的MySQL表,其中包含值(直接从MySQL控制台输出):

mysql> select * from temp; +------+-----------------------------------------------+ | id | value | +------+-----------------------------------------------+ | 1 | this is a first item | | 2 | this is the second item | | 3 | This is the third item and slightly redundant | +------+-----------------------------------------------+ 3 rows in set (0.00 sec) 

在Java中,我正在访问数据库,如下所示:

 stmt = conn.prepareStatment("select * from ?"); stmt.setString(1,"temp"); ResultSet rs = stmt.executeQuery(); //This method call throws the exception 

stmt.toString显示: select * from 'temp' stmt.toString select * from 'temp' ,exception消息是: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near ''temp'' at line 1 You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near ''temp'' at line 1

当我select * from 'temp'stmt.toString()的输出中select * from 'temp'直接进入MySQL控制台时,我得到完全相同的消息。

正如您可能想象的那样,我计划将此概念应用于JSP网页,其中表名称将是HTTP GET参数。 所以我的问题是:如何将表名绑定到准备好的语句,如果不可能(这是我从PHP的类似问题得到的氛围),我将如何清理表名的输入?

你不能这样做。 您需要使用字符串连接构造sql。 PreparedStatement用于列值而不是表名。

您不能对表名使用stmt.setString()setInt()函数,它仅对列值有效。

这种要求指出了数据库设计中的缺陷。 如果您的“主题”表包含不同的信息,您如何使用相同的查询来检索该信息?

您正在从表中选择所有列,并使您的应用程序对其执行和不需要的内容进行排序。 这会在您的应用程序中产生风险和漏洞,在您的通信渠道上产生冗余数据传输,并在您的应用程序变得流行时难以进行数据库优化。 我怀疑你的应用程序代码是一个纠结的if和case来整理回来的列。 如果您合理化该代码,以便每个表格式都是已知的并由特定类处理,那么您的代码将更加简单,并且您的表名称不再是参数。

由于创建SQL注入漏洞,替换表名也会产生难以克服的安全问题。 如果有人给你(fish INNER JOIN mysql.user ON TRUE)表名称怎么办? 这与您的全列选择一起将为他们提供您的MySQL用户表! 你想要那个吗?? 转义表值对你没有任何帮助。 事实上,它只会为攻击者提供更广泛的字符,这些字符可以注入到SQL语句中。

您需要做的是将数据库设计合理化并规范化为具有“主题”列的表,您可以使用预准备语句参数进行选择。