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

时间:2014-09-12 15:19:29

标签: java sql intellij-idea derby

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

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

5 个答案:

答案 0 :(得分:4)

代码中存在两个问题:

  1. SQL语句最后不需要分号;。它会使代码失败。

  2. 代码很容易出现SQL注入,很难维护。改为使用PreparedStatement

  3. 这应该是工作代码:

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

答案 1 :(得分: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 出现在您的错误消息中。

答案 2 :(得分: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...if更改为if...else if,因为我认为CDAlbum也不太可能是DVDAlbum。命名注释 - 类名中的首字母缩略词最好用单词表示 - DvdAlbum而不是DVDAlbum

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

虽然将完全不同的数据存储在同一个表中的整个想法是设计问题的明确标志。此外,像tracks这样的字段 - 肯定需要另一个表格?!

答案 3 :(得分:0)

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

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

答案 4 :(得分:0)

您需要转义'字符串中的所有cdAlbum.getTitle(), cdAlbum.getGenre(), cdAlbum.getArtist(), cdAlbum.getTracks()字符。

更好的是,使用prepared statement它会为你处理这个问题,作为奖励你不会受到SQL注入的攻击。