SQL语法错误尝试将行插入表时出现exception

嗨我在执行以下function时遇到问题而没有遇到以下exception。 我不确定为什么会这样。 我认为它可能与引号有关。 如果重要的话,我正在使用德比数据库。

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 

代码中的两个问题:

  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参数将为您转义任何'"以及其他字符。

XKCD SQL注入 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构造,这将始终关闭资源。 如果查询中存在错误,则当前代码存在内存泄漏 – 将抛出exception并跳过close()调用。 在许多地方,当您阅读文件,打开连接等时,您会遇到此问题…

我也改变了你的if...if to if...else if我认为CDAlbum也不太可能是DVDAlbum 。 命名注释 – 类名中的首字母缩略词最好用词DvdAlbum而不是DVDAlbum

此外,我建议您了解方法重载以及多态。 如果代码中的instanceof是代码气味的确定标志,则任何用途。

虽然将完全不同的数据存储在同一个表中的整个想法是设计问题的明确标志。 此外,像tracks这样的领域 – 当然需要另一张桌子?!

这可能是“不要为我哭泣,阿根廷”。 你看到了吗?

您可以使用错误的值来破坏安全性。

最好使用准备好的声明:

  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添加。

无论抛出exception/返回/中断,try-with-resources都会关闭statement

PS“不要”可能是罪魁祸首,撇号结束引用的文本,并且t出现在您的错误消息中。

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

我不认为两个; 需要。 最好调试代码并在DB中进行SQL查询和测试。

你需要转义你的cdAlbum.getTitle(), cdAlbum.getGenre(), cdAlbum.getArtist(), cdAlbum.getTracks()字符串中的任何'字符。

更好的是,使用准备好的声明 ,它将为您处理这个,作为奖励,您将不会受到SQL注入的攻击。