2014-09-12 51 views
2

您好,我在執行以下功能時遇到了問題,但未遇到以下異常。我不知道爲什麼會發生這種情況。我認爲這可能與報價有關。如果它很重要,我正在使用德比數據庫。嘗試向表格中插入行時出現SQL語法錯誤例外

java.sql.SQLSyntaxErrorException 

這是下面的代碼,我試圖執行:

public void addAlbum(Album album) throws IOException, SQLException { 
    Properties props = new Properties(); 
    FileInputStream in = new FileInputStream("database.properties"); 
    props.load(in); 
    in.close(); 

    props.getProperty("jdbc.drivers"); 
    String url = props.getProperty("jdbc.url"); 
    String username = props.getProperty("jdbc.username"); 
    String password = props.getProperty("jdbc.password"); 

    Connection connection = DriverManager.getConnection(url, username, password); 
    Statement statement = connection.createStatement(); 
    String sql = null; 

    if(album instanceof CDAlbum) { 
     CDAlbum cdAlbum = (CDAlbum)album; 
     sql = "INSERT INTO MyAlbums VALUES ('CD', '" + cdAlbum.getTitle() + "', '" + cdAlbum.getGenre() + "','" + cdAlbum.getArtist() + "', '" + cdAlbum.getTracks() + "');"; 
    } 
    if(album instanceof DVDAlbum) { 
     DVDAlbum dvdAlbum = (DVDAlbum)album; 
     sql = "INSERT INTO MyAlbums VALUES ('DVD', '" + dvdAlbum.getTitle() + "', '" + dvdAlbum.getGenre() + "','" + dvdAlbum.getDirector() + "', '" + dvdAlbum.getPlotOutline() + "');"; 
    } 

    statement.executeUpdate(sql); 
    System.out.println("Album Added!"); 

    if(statement != null) { 
     statement.close(); 
    } 
    if(connection != null) { 
     connection.close(); 
    } 
} 

這是例外:

java.sql.SQLSyntaxErrorException: Syntax error: Encountered "t" at line 2, column 5. 
at org.apache.derby.impl.jdbc.SQLExceptionFactory.getSQLException(Unknown Source) 
at org.apache.derby.impl.jdbc.Util.generateCsSQLException(Unknown Source) 
at org.apache.derby.impl.jdbc.TransactionResourceImpl.wrapInSQLException(Unknown Source) 
at org.apache.derby.impl.jdbc.TransactionResourceImpl.handleException(Unknown Source) 
at org.apache.derby.impl.jdbc.EmbedConnection.handleException(Unknown Source) 
at org.apache.derby.impl.jdbc.ConnectionChild.handleException(Unknown Source) 
at org.apache.derby.impl.jdbc.EmbedStatement.execute(Unknown Source) 
at org.apache.derby.impl.jdbc.EmbedStatement.executeLargeUpdate(Unknown Source) 
at org.apache.derby.impl.jdbc.EmbedStatement.executeUpdate(Unknown Source) 
at au.edu.uow.CollectionDB.MyCollectionDB.addAlbum(MyCollectionDB.java:194) 
at au.edu.uow.Collection.CollectionFactory.loadCollection(CollectionFactory.java:136) 
at MyCollection.main(MyCollection.java:18) 
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) 
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57) 
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) 
at java.lang.reflect.Method.invoke(Method.java:606) 
at com.intellij.rt.execution.application.AppMain.main(AppMain.java:120) 
Caused by: ERROR 42X01: Syntax error: Encountered "t" at line 2, column 5. 
at org.apache.derby.iapi.error.StandardException.newException(Unknown Source) 
at org.apache.derby.iapi.error.StandardException.newException(Unknown Source) 
at org.apache.derby.impl.sql.compile.ParserImpl.parseStatementOrSearchCondition(Unknown Source) 
at org.apache.derby.impl.sql.compile.ParserImpl.parseStatement(Unknown Source) 
at org.apache.derby.impl.sql.GenericStatement.prepMinion(Unknown Source) 
at org.apache.derby.impl.sql.GenericStatement.prepare(Unknown Source) 
at org.apache.derby.impl.sql.conn.GenericLanguageConnectionContext.prepareInternalStatement(Unknown Source) 
... 11 more 

回答

4

兩個問題:

  1. SQL語句不需要在結束分號;。它會使代碼失敗。

  2. 該代碼很容易出現SQL注入並且很難維護。使用PreparedStatement代替:

這應該是工作代碼:

String sql = "INSERT INTO MyAlbums VALUES (?, ?, ?, ?, ?)"; 
PreparedStatement pstmt = connection.prepareStatement(sql); 
if(album instanceof CDAlbum) { 
    pstmt.setString(1, "CD"); 
    CDAlbum cdAlbum = (CDAlbum)album; 
    pstmt.setString(4, cdAlbum.getArtist()); 
    pstmt.setString(5, cdAlbum.getTracks()); 
} 
if(album instanceof DVDAlbum) { 
    pstmt.setString(1, "DVD"); 
    DVDAlbum dvdAlbum = (DVDAlbum)album; 
    pstmt.setString(4, dvdAlbum.getDirector()); 
    pstmt.setString(5, dvdAlbum.getPlotOutline()); 
} 
pstmt.setString(2, album.getTitle()); 
pstmt.setString(3, album.getGenre()); 
pstmt.executeUpdate(); 

普通字符串連接而這種做法對於你的情況之間的不同的是,PreparedStatement參數會逃跑任何'"和其他字符爲你。

0
sql = "INSERT INTO MyAlbums VALUES ('DVD', '" + dvdAlbum.getTitle() + "', '" + dvdAlbum.getGenre() + "','" + dvdAlbum.getDirector() + "', '" + dvdAlbum.getPlotOutline() + "');"; 

我我不知道有;需要。更好地調試代碼並在數據庫中進行SQL查詢和測試。

0

您需要轉義cdAlbum.getTitle(), cdAlbum.getGenre(), cdAlbum.getArtist(), cdAlbum.getTracks()字符串中的任何'字符。

更好的是,使用prepared statement,它會爲您處理這個問題,作爲獎勵,您不會受到SQL注入的攻擊。在你的代碼

3

它可能是「不要爲我哭,阿根廷」。你看到了嗎?

您可以通過錯誤的值破壞安全性。

最好使用事先準備好的聲明:

String sql = "INSERT INTO MyAlbums(Title, Genre, X, Y) VALUES (?, ?, ?, ?, ?)"; 
    try (Statement statement = connection.createPreparedStatement(sql)) { 
     if(album instanceof CDAlbum) { 
      CDAlbum cdAlbum = (CDAlbum)album; 
      statement.setString(1, "CD"); 
      statement.setString(2, cdAlbum.getTitle()); 
      statement.setString(3, cdAlbum.getGenre()); 
      statement.setString(4, cdAlbum.getArtist()); 
      statement.setString(5, cdAlbum.getTracks()); 
     } else if(album instanceof DVDAlbum) { 
      DVDAlbum dvdAlbum = (DVDAlbum)album; 
      statement.setString(1, "DVD"); 
      statement.setString(2, dvdAlbum.getTitle()); 
      statement.setString(3, dvdAlbum.getGenre()); 
      statement.setString(4, dvdAlbum.getDirector()); 
      statement.setString(5, dvdAlbum.getPlotOutline()); 
     } 
     int updateCount = statement.executeUpdate(); 
     System.out.println("Album Added! (" + updateCount + " Records updated)"); 
    } 

我增加了一些列名的好措施爲表計劃未來的變化。並且updateCount應該給1添加。

無論是否引發異常/返回/中斷,try-with-resources關閉statement

P.S. 「不要」可能是罪魁禍首,撇號結束引用的文字,並且t出現在您的錯誤消息中。

3

XKCD SQL injection XKCD#327(http://xkcd.com/327/

使用PreparedStatement

可能,我建議:

try (final PreparedStatement preparedStatement = con.prepareStatement(sql)) { 
    if (album instanceof CDAlbum) { 
     CDAlbum cdAlbum = (CDAlbum) album; 
     preparedStatement.setString(1, "CD"); 
     preparedStatement.setString(2, cdAlbum.getTitle()); 
     preparedStatement.setString(3, cdAlbum.getGenre()); 
     preparedStatement.setString(4, cdAlbum.getArtist()); 
     preparedStatement.setString(5, cdAlbum.getTracks()); 
    } else if (album instanceof DVDAlbum) { 
     DVDAlbum dvdAlbum = (DVDAlbum) album; 
     preparedStatement.setString(1, "DVD"); 
     preparedStatement.setString(2, dvdAlbum.getTitle()); 
     preparedStatement.setString(3, dvdAlbum.getGenre()); 
     preparedStatement.setString(4, dvdAlbum.getDirector()); 
     preparedStatement.setString(5, dvdAlbum.getPlotOutline()); 
    } 
    dvdAlbum.getPlotOutline(); 
} 

這樣可以防止導致查詢失敗的數據怪異值的任何可能性。另請注意,我使用try-with-resources結構,這將始終關閉資源。如果查詢中存在錯誤,您當前的代碼會發生內存泄漏 - 將拋出異常並跳過close()調用。你有這樣的問題,在很多地方,當你閱讀文件,當您打開連接,等等

我也改變了你的if...ifif...else if,我想這是不可能的CDAlbum也將是一個DVDAlbum 。命名註釋 - 類名稱中的首字母縮寫最好用文字表示 - DvdAlbum而不是DVDAlbum

此外,我建議您瞭解方法重載以及多態性。如果代碼中的instanceof是代碼異味的確切標誌,則可以使用。

雖然將完全不同的數據存儲在同一個表中的整個想法是設計問題的肯定標誌。此外,字段tracks - 當然,這需要另一張桌子?!

相關問題