0

したがって、データをテーブルにロードするプロセスがあります。これに先立って、ターゲットの指示 (変更不可) に従って、監査レコードは次のようなテーブルに配置されます。

INSERT INTO audit VALUES (SELECT (MAX(batch_id) + 1), "feedname" from audit).

ここで、10 個の並列ロード プロセスが開始され、すべて異なるフィード名が付けられます。接続は Java 経由で行われ、すべて自動コミットをオンにしてステートメントを実行しています。

ただし、batch_id 主キー制約により、これらは互いに衝突しています。

私の発言の何が問題になっていますか?

4

1 に答える 1

0

マルチスレッド環境では、select ステートメントが挿入の前に発生するため、2 つのスレッドが同じ値の batch_id を参照できます。たとえば、次の処理が順番に行われていると想像してください。

Thread 1: 
SELECT (MAX(batch_id) + 1) # returns 1
Thread 2:
SELECT (MAX(batch_id) + 1) # returns 1 again, nothing has changed
Thread 1:
INSERT INTO audit VALUES (1, "feedname"); # because 1 was SELECTed before 
Thread 2:
INSERT INTO audit VALUES (1, "feedname"); #crash!

データベースがサポートしている場合は、シーケンスまたは自動インクリメント主キーを使用してください。

編集:OPのコメントに応じた回避策

1.次の SQL ステートメントを使用して、次の batch_id 値を Java 変数に取得し、プロセスを初期化します。

 SELECT (MAX(batch_id) + 1) from audit;

2. 同期された Java メソッドを使用して、次の ID を取得します。

 private synchronized int getNextBatchId() {
   return nextId++;
 }

3.Prepared Statements でメソッドを使用する:

 PreparedStatement ps = connection.prepareStatement("INSERT INTO audit VALUES (?, 'feedname')");
 ps.setInt(1, getNextBatchId());
 ps.execute();
于 2013-09-16T09:23:05.560 に答える