コードはキューからデータを取得し、それを準備済みステートメントにバッチとして追加し、バッチを実行してからコミットします。
int counter = 0;
while (!this.dataQueue.isEmpty()
&& counter <= config.MAX_FLUSH_COUNT) {
DataRecord record = this.dataQueue.poll();
if (record.ip.length() > 40) {
record.ip = record.ip.substring(0, 40);
}
try {
this.dataFlush.setInt(1, record.uid);
this.dataFlush.setInt(2, record.fid);
this.dataFlush
.setTimestamp(3, new Timestamp(record.time));
this.dataFlush.setString(4, record.ip);
this.dataFlush.addBatch();
} catch (Exception ex) {
Log.logError("Error building record: " + ex.getMessage());
}
counter++;
}
if (counter > 0) {
try {
this.dataFlush.executeBatch();
this.dataFlush.getConnection().commit();
} catch (SQLException ex) {
Log.logError("Error executing flush: " + ex.getMessage());
}
}
このフラッシュには数千のエントリ (MAX_FLUSH_COUNT でバッチあたり 2000 に制限) が含まれる可能性があるため、デッドロックが発生することがあります (フラッシュは 8 秒ごとに実行され、デッドロックは約 5 ~ 6 時間ごとに発生します)。
編集:これは私の準備されたステートメントです:
Connection conn = DBBase.getConnection();
conn.setAutoCommit(false);
this.snatchFlush = conn.prepareStatement("INSERT INTO slog (uid, fid, time, ip) VALUES (?, ?, ?, ?) ON DUPLICATE KEY UPDATE fid=VALUES(fid), time=VALUES(time), ip=VALUES(ip)");
uid は、このテーブルの主キーです。データベース エンジンは InnoDB であり、外部キーもトリガーもありません。このテーブルは、Web サーバーとこのアプリケーションによって同時に読み書きされる可能性がありますが、これはほとんどありませんが可能です。
最初の変更は、バッチを複数のバッチに分割し、そのサイズを 200 ~ 500 データセットに制限することです。
今の問題: デッドロックが発生した場合、通常の解決策はトランザクションを再開することです。
これは、データを dataFlush Prepared Statement に再度追加し、executeBatch して再度コミットする必要があるということですか? はいの場合、キューからポーリングされたデータを保存する必要があることを意味します。そうしないとデータが失われるためです。
ポーリングされたデータを保存する必要のない、より良い解決策はありますか? (executeBatchはバッチデータを削除するため、catch-Blockでの単純なexecuteBatchとcommitは機能しないと想定しています)。