【问题标题】:SQL Syntax Error Exception when trying to insert row into table尝试将行插入表时出现 SQL 语法错误异常
【发布时间】:2014-09-12 15:19:28
【问题描述】:

您好,我在执行以下功能时遇到了问题,但没有遇到以下异常。我不确定为什么会这样。我认为这可能与引号有关。如果重要的话,我正在使用 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

【问题讨论】:

    标签: java sql intellij-idea derby


    【解决方案1】:

    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 这样的字段 - 肯定需要另一个表吗?!

    【讨论】:

      【解决方案2】:

      您的代码中有两个问题:

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

      【讨论】:

        【解决方案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 与抛出的异常/返回/中断无关。

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

        【讨论】:

          【解决方案4】:
          sql = "INSERT INTO MyAlbums VALUES ('DVD', '" + dvdAlbum.getTitle() + "', '" + dvdAlbum.getGenre() + "','" + dvdAlbum.getDirector() + "', '" + dvdAlbum.getPlotOutline() + "');";
          

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

          【讨论】:

            【解决方案5】:

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

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

            【讨论】:

              猜你喜欢
              • 2019-08-09
              • 1970-01-01
              • 2022-01-20
              • 1970-01-01
              • 2014-08-10
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              相关资源
              最近更新 更多