我正在尝试学习如何在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的类似问题得到的氛围),我将如何清理表名的输入?
答案 0 :(得分:1)
你做不到。您需要使用字符串连接构造sql。 PreparedStatement
用于列值而非表名。
答案 1 :(得分:1)
您不能对表名使用stmt.setString()
或setInt()
函数,它仅对列值有效。
答案 2 :(得分:0)
这种要求指出了数据库设计中的缺陷。如果您的“主题”表包含不同的信息,您如何使用相同的查询来检索该信息?
您正在从表中选择所有列,并使您的应用程序对其执行和不需要的内容进行排序。这会在您的应用程序中产生风险和漏洞,在您的通信渠道上产生冗余数据传输,并在您的应用程序变得流行时难以进行数据库优化。我怀疑你的应用程序代码是一个纠结的if和case来整理回来的列。如果您合理化该代码,以便每个表格式都是已知的并由特定类处理,那么您的代码将更加简单,并且您的表名称不再是参数。
由于创建SQL注入漏洞,替换表名也会产生难以克服的安全问题。如果某人为您提供(fish INNER JOIN mysql.user ON TRUE)
表名,该怎么办?那个,与你的全列选择一起将为他们提供你的MySQL用户表!你想要那个吗??转义表值对你没有任何帮助。实际上,它只会为攻击者提供更多的字符,这些字符可以注入到SQL语句中。
您需要做的是将数据库设计合理化并规范化为具有“主题”列的表,您可以使用预准备语句参数选择该列。