0

大きな行を挿入するための安らかなサービスを構築しました。大量の行を挿入するには、バッチで挿入を使用しています。この安らかなサービスのスニペットでデッドロックが発生する原因は何ですか。

    final SqlMapClient sqlMapClient = getSqlMapClientTemplate().getSqlMapClient();
    sqlMapClient.startTransaction();
    sqlMapClient.startBatch();

    //data is of size say 10,000 i am dividing into 500 and inserting
    do {
        data500 = next 500 of data
        getSqlMapClientTemplate().insert("insertData", data500);  
    }while(data500 is not empty)

    sqlMapClient.executeBatch();
    sqlMapClient.commitTransaction();

しかし、私はこのエラーが発生しています:

 
説明 : org.springframework.dao.ConcurrencyFailureException: SqlMapClient 操作。SQL [];   
--- パラメータ マップの適用中にエラーが発生しました。   
--- insertData-InlineParameterMap を確認してください。   
--- ステートメントを確認してください (更新に失敗しました)。   
--- 原因: java.sql.SQLException: トランザクション (プロセス ID 3121) が別のプロセスのロック リソースでデッドロックされ、デッドロックの対象として選択されました。トランザクションを再実行してください。; ネストされた例外は com.ibatis.common.jdbc.exception.NestedSQLException:

4

1 に答える 1

0

デッドロックは、プログラムの設計上の問題を示しています。データベースは、データが変更されるとデータをロックするトランザクションを作成します。データ「A」を変更してからデータ「B」を変更すると、データベースではこれらのデータ ポイントが両方ともロックされます。データベースと設定に応じて、'A' と 'B' の実際のロックは、個々のレコード、レコード (ページ) のグループ、またはテーブル全体である可能性があります。

トランザクションが「A」をすでに変更しており、現在「B」を変更しようとしているが、他のプログラムが「B」をすでに変更しており、現在「A」を変更しようとしている場合、デッドロックが発生します。

一部のデータベース (DB2 など) は、ロックのタイムアウト (プロセスがロックを取得するために 60 秒間試みたが失敗した) であっても、デッドロックがあることを示しています。DB2 には、根本的なデッドロックの原因を示す特別なサブコードがあります。

デッドロックの唯一の解決策は、データベースが強制終了するプロセスの 1 つを選択し、他のプロセスを通過させることです。プロセスが強制終了されました。

デッドロックの問題は、プログラムの設計上の問題を示しています。これはよく知られた問題であり、信頼できる唯一の解決策は、すべてのプログラムが互いに同じ順序でデータをロックするようにすることです。これにより、デッドロックが発生しなくなります。デッドロックのもう 1 つの一般的な理由は、ロジック内の適切な場所で作業をコミットしないプログラムです。

編集-あなたの場合、500のバッチでそれらを挿入していると主張しますが、開始/コミットはすべての最初と最後にあります。start/execute Batch と start/commit Transactionをループ内に配置する必要があります。挿入されるすべてのレコードのロックを保持しています

//data is of size say 10,000 i am dividing into 500 and inserting
do {
    sqlMapClient.startTransaction();
    sqlMapClient.startBatch();

    data500 = next 500 of data
    getSqlMapClientTemplate().insert("insertData", data500);  

    sqlMapClient.executeBatch();
    sqlMapClient.commitTransaction();
}while(data500 is not empty)

または、デッドロックは「再試行可能な」エラーです。デッドロックが発生した場合は、SQL を再実行して結果を取得できます (今回はデッドロックが発生しないことを願っています)。

于 2013-05-07T14:06:03.237 に答える