简体   繁体   English

MySQL插入错误?

[英]MySQL Insert error?

I am writing a program that tracks sales for a local business. 我正在编写一个跟踪本地企业销售情况的程序。 I wrote a method to export a table to a csv file, then right after load that csv file into a new table for archiving purposes; 我编写了一种将表导出到csv文件中的方法,然后将该csv文件加载到新表中以进行存档之后; however, when it runs through the method archive() it will only run through the while loop once, works but then on the second loop through it gives me this error: 但是,当它通过方法archive()运行时,它将仅在while循环中运行一次,并且可以运行,但是在通过它的第二个循环中,却出现了以下错误:

com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: Unknown column 'N' in 'field list'
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:57)
at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
at java.lang.reflect.Constructor.newInstance(Constructor.java:525)
at com.mysql.jdbc.Util.handleNewInstance(Util.java:411)
at com.mysql.jdbc.Util.getInstance(Util.java:386)
at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:1052)
at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:3609)
at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:3541)
at com.mysql.jdbc.MysqlIO.sendCommand(MysqlIO.java:2002)
at com.mysql.jdbc.MysqlIO.sqlQueryDirect(MysqlIO.java:2163)
at com.mysql.jdbc.ConnectionImpl.execSQL(ConnectionImpl.java:2618)
at com.mysql.jdbc.StatementImpl.executeUpdate(StatementImpl.java:1749)
at com.mysql.jdbc.StatementImpl.executeUpdate(StatementImpl.java:1666)
at serverarchiver.ServerGui.archive(ServerGui.java:118)
at serverarchiver.ServerGui.run(ServerGui.java:144)
at java.lang.Thread.run(Thread.java:722)

Here is the relevant code: 以下是相关代码:

 public void archive(){
      try {

             //Archive and new table

             stmt.executeQuery("SELECT * INTO OUTFILE '"+ getMonth()+"" +  getYear() +  ".csv' FIELDS TERMINATED BY ',' FROM last");
             stmt.executeUpdate("CREATE  TABLE `lastdb`.`"+ getMonth()+"" +  getYear() +  "` (`Name` VARCHAR(50) NOT NULL ,`Goal` INT  NOT NULL ,`New` INT NOT NULL , `Used` INT NOT NULL  , `Total` INT NOT NULL , `Pace` INT NOT NULL  ,PRIMARY KEY (`Name`, `Goal`, `New`, `Used`, `Total`, `Pace`) );");

             CSVReader reader = new CSVReader(new FileReader("C:/ProgramData/MySQL/MySQL Server 5.5/data/lastdb/"+getMonth()+"" +  cal.getInstance().get(Calendar.YEAR) +  ".csv"));
             String[] nextLine;

             while((nextLine = reader.readNext()) != null){
                 stmt.executeUpdate("INSERT INTO `lastdb`.`"+ getMonth()+"" +  cal.getInstance().get(Calendar.YEAR) +  "` (`Name`, `Goal`, `New`, `Used`, `Total`, `Pace`) VALUES ('"+ nextLine[0]+ "', " +nextLine[1]+ " , " +nextLine[2]+ "  , " +nextLine[3]+ "  , " +nextLine[4]+ "  , " +nextLine[5]+ ")");
             }
         }catch(FileNotFoundException e){
            e.printStackTrace();
         }catch(IOException ed){
            ed.printStackTrace();
         }catch(SQLException eds){
            eds.printStackTrace();
         }
 }

That can only be caused by a SQL injection attack of the CSV file which you're reading. 这只能由您正在读取的CSV文件的SQL注入攻击引起。

In other words, the SQL string which you're concatenating there with unvalidated CSV values could have resulted in a malformed SQL string. 换句话说,您在此处与未经验证的CSV值连接的SQL字符串可能导致SQL字符串格式错误。 I suggest to do a System.out.println() of the populated SQL string before it's been executed, so that you can check what exactly made the SQL query invalid. 我建议在执行之前对填充的SQL字符串执行System.out.println() ,以便您可以检查究竟是什么使SQL查询无效。

You can fix it by escaping the CSV values accordingly, but best solution would be to use PreparedStatement instead of Statement . 您可以通过转义CSV值来解决它,但是最好的解决方案是使用PreparedStatement而不是Statement Eg 例如

preparedStatement = connection.prepareStatement("INSERT INTO `lastdb`.`" + getMonth() + "" +  cal.getInstance().get(Calendar.YEAR) 
    + "` (`Name`, `Goal`, `New`, `Used`, `Total`, `Pace`) VALUES (?, ?, ?, ?, ?, ?)");

while ((nextLine = reader.readNext()) != null) {
    // ...
    preparedStatement.setString(1, nextLine[0]);
    preparedStatement.setString(2, nextLine[1]);
    preparedStatement.setString(3, nextLine[2]);
    preparedStatement.setString(4, nextLine[3]);
    preparedStatement.setString(5, nextLine[4]);
    preparedStatement.setString(6, nextLine[5]);
    preparedStatement.executeUpdate();
}

It not only escapes column values, but it also improves performance. 它不仅转义了列值,而且还提高了性能。 You can even improve it further by using batches by addBatch() and executeBatch() . 您甚至可以通过addBatch()executeBatch()使用批处理来进一步改进它。

while ((nextLine = reader.readNext()) != null) {
    // ...
    preparedStatement.setString(1, nextLine[0]);
    preparedStatement.setString(2, nextLine[1]);
    preparedStatement.setString(3, nextLine[2]);
    preparedStatement.setString(4, nextLine[3]);
    preparedStatement.setString(5, nextLine[4]);
    preparedStatement.setString(6, nextLine[5]);
    preparedStatement.addBatch();
}

preparedStatement.executeBatch();

See also: 也可以看看:

So you want to move the entire table into a new table without changing anything. 因此,您希望将整个表移到新表中而不进行任何更改。

Have you considered simply renaming the table and creating a new? 您是否考虑过简单地重命名表并创建一个新表?

RENAME TABLE last TO lastdb.<month><year>;
CREATE TABLE last LIKE lastdb.<month><year>;

That's going to be lightning fast and much safer. 那将是闪电般的快,而且更加安全。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM