传递表名作为预准备语句的参数

时间:2014-01-19 06:08:40

标签: java mysql sql prepared-statement

我正在尝试学习如何在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' 并且异常消息是: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()的输出)直接输入MySQL控制台时,我得到完全相同的消息。

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

3 个答案:

答案 0 :(得分:1)

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

答案 1 :(得分:1)

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

答案 2 :(得分:0)

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

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

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

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