2014-01-19 59 views
2

我試圖學習如何使用MySQL和Java,並且標題所示,我在準備語句時遇到問題。傳遞表名作爲準備語句的參數

我有一個MySQL表名爲temp這(直接輸出從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中,我訪問DB這樣的:

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

是的,我看到了,但答案並不是非常有信心或對此有幫助。爲了未來遇到這個問題的每一個人,我希望得到更好的答案或解決問題的辦法,這不會犧牲安全性。 – Alex

+0

你不應該需要淨化一個表名(不像表單數據),所以我不明白這是一個問題。 – blackcompe

+0

我想要製作一個帶有多個卡片主題的flashcard程序,所以我希望每個主題都是不同的表格(不同的主題可能需要存儲不同的信息)。 – Alex

回答

1

你不能那樣做。你需要用字符串連接構造sql。 PreparedStatement適用於不適用於表名稱的列值。

+0

不!不要使用外部提供的表名稱值! –

1

您不能使用stmt.setString()setInt()函數作爲表名,它僅適用於列值。

0

這種要求指出了數據庫設計中的缺陷。如果您的「主題」表包含不同的信息,您如何使用相同的查詢來檢索該信息?

您正在選擇表格中的所有列,並讓您​​的應用程序清理它所做的和不想要的。這會在您的應用程序中產生風險和漏洞,在您的通信渠道中傳輸冗餘數據,以及在您的應用程序變得流行時遇到數據庫優化困難。我懷疑你的應用程序代碼是一堆糾結的if和case來整理回來的列。如果您合理化代碼以便每個表格格式都是已知的並且由特定類別處理,那麼您的代碼將會簡單得多,並且您的表格名稱不必再是參數。

替換表名還會因創建SQL注入漏洞而創建難以克服的安全問題。如果有人給你(fish INNER JOIN mysql.user ON TRUE)表名稱會怎麼樣。這與您的所有列選擇一起將爲您提供您的MySQL用戶表!你想要那個嗎??轉換表值並不能幫助你。實際上,它只會給攻擊者提供更多可以注入SQL語句的字符。

你需要做的是合理化和規範化數據庫設計成有一個「主題」欄,你可以用準備好的聲明中參數選擇一個表什麼。

相關問題