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 PM org.apache.hadoop.mapred.LocalJobRunner$Job run 警告: job_local_0001 java.io.IOException: org.apache.hadoop.mapred のキー「PRIMARY」のエントリ「505975648」が重複しています。 org.apache.hadoop.mapred.ReduceTask$OldTrackingRecordWriter.close(ReduceTask.java:467) の lib.db.DBOutputFormat$DBRecordWriter.close(DBOutputFormat.java:77) 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 は、データベース トランザクションですべてを行います。現時点ではテーブルに何もないかもしれませんが、同じトランザクションで同じ主キーを使用して 2 つの挿入を行おうとすると、このエラーが発生します。これが実際に起こっていることです。これをよりよく追跡するために、ログを追加できます。これを行うには、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 に答える