MySQL插入错误?

时间:2011-11-23 19:16:46

标签: java mysql jdbc

我正在撰写一个跟踪当地企业销售情况的计划。我写了一个方法将表导出到csv文件,然后在将csv文件加载到新表中以便存档之后立即执行;但是,当它运行方法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)

以下是相关代码:

 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();
         }
 }

2 个答案:

答案 0 :(得分:1)

这只能由您正在阅读的CSV文件的SQL注入攻击引起。

换句话说,使用未经验证的CSV值连接的SQL字符串可能导致格式错误的SQL字符串。我建议在执行之前对填充的SQL字符串执行System.out.println(),以便您可以检查究竟是什么使SQL查询无效。

您可以通过相应地转义CSV值来修复它,但最好的解决方案是使用PreparedStatement而不是Statement。 E.g。

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();
}

它不仅可以转义列值,还可以提高性能。您甚至可以通过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();

另见:

答案 1 :(得分:0)

因此,您希望将整个表移动到新表中而不进行任何更改。

您是否只考虑了renaming表并创建了一个新的?

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

这将是闪电般快速,更安全。