0

插入表时面临重复条目问题。

我一直在使用 Hadoop 映射器从文件中读取记录。它成功地从文件中完全读取记录​​。但是在通过 Hadoop 减速器将记录写入 mysql 数据库时,出现以下错误。

java.io.IOException:键“PRIMARY”的重复条目“505975648”

但是 Mysql 表仍然是空的。无法从 Hadoop DBWritable reducer 将记录写入 mysql 表。

以下是错误日志:

警告:com.mysql.jdbc.exceptions.jdbc4.MySQLNonTransientConnectionException:Connection.close() 已经被调用。此状态下的无效操作。在 sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method) 在 sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:57) 在 sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45) 在 java.lang.reflect.Constructor .newInstance(Constructor.java:526) 在 com.mysql.jdbc.Util.handleNewInstance(Util.java:406) 在 com.mysql.jdbc.Util.getInstance(Util.java:381) 在 com.mysql.jdbc。 SQLError.createSQLException(SQLError.java:984) 在 com.mysql.jdbc.SQLError.createSQLException(SQLError.java:956) 在 com.mysql.jdbc.SQLError.createSQLException(SQLError.java:926) 在 com.mysql.jdbc .

2014 年 6 月 4 日下午 1:23:36 org.apache.hadoop.mapred.LocalJobRunner$Job 运行警告:job_local_0001 java.io.IOException: org.apache.hadoop.mapred 中键“PRIMARY”的重复条目“505975648”。 lib.db.DBOutputFormat$DBRecordWriter.close(DBOutputFormat.java:77) at org.apache.hadoop.mapred.ReduceTask$OldTrackingRecordWriter.close(ReduceTask.java:467) at org.apache.hadoop.mapred.ReduceTask.runOldReducer( ReduceTask.java:531) 在 org.apache.hadoop.mapred.ReduceTask.run(ReduceTask.java:421) 在 org.apache.hadoop.mapred.LocalJobRunner$Job.run(LocalJobRunner.java:262)

4

1 回答 1

1

DBOutputFormat / DBRecordWriter 在数据库事务中执行所有操作。虽然您现在表中可能没有任何内容,但如果您尝试在同一个事务中使用相同的主键进行两次插入,您将收到此错误,这就是正在发生的事情。为了更好地跟踪这一点,您可以添加日志记录。您可以通过获取 DBOutputFormat 的代码并创建一个新的类似名称的类来做到这一点。我叫我的 LoggingDBOutputFormat。更新您的工作代码以改用这种新的输出格式。对于新的输出格式,您可以更改 close 方法以在执行语句之前记录语句:

    /** {@inheritDoc} */
public void close(TaskAttemptContext context) throws IOException {
  try {
      LOG.warn("Executing statement:" + statement);   

      statement.executeBatch();
    connection.commit();
  } catch (SQLException e) {
    try {
      connection.rollback();
    }
    catch (SQLException ex) {
      LOG.warn(StringUtils.stringifyException(ex));
    }
    throw new IOException(e.getMessage());
  } finally {
    try {
      statement.close();
      connection.close();
    }
    catch (SQLException ex) {
      throw new IOException(ex.getMessage());
    }
  }
}

然后,您可以检查 mysql 端的常规日志以查看是否执行了任何操作。很可能您会看到您的事务因错误而被回滚。要解决此问题,请确保主键是唯一的。如果更新/更新插入是您想要的,您可以制作一个输出/记录编写器来执行此操作,但这是一项不同的工作。

于 2014-10-30T22:02:01.877 回答