2

現在、Spring Hibernate (サービスおよび daoImpl クラスのアノテーションによるトランザクション) で競合の問題が発生しています。これが私が遭遇したものです:

テーブル:

  • デバイスの種類: ID (シリアル)、名前
  • デバイス: id (シリアル)、device_identifier、device_type_id、ip_address

device_identifier と device_type_id は共に一意であることに注意してください

マルチスレッドプロセスで私が持っているもののスニペットは次のとおりです。

    if(deviceDao.findByIdentifierAndTypeId(identifier, typeId) == null){
        Device newDevice = new Device();
        newDevice.setIdentifier(identifier);
        newDevice.setTypeId(typeId);
        deviceDao.add(newDevice);
    }

何が起こるかというと、websocket 経由でデバイスをリッスンするサーバーがあり (ここではおそらく重要な詳細ではない)、サーバーは最初にデバイスがデータベースに既に存在するかどうかを判断しようとし、まだ見つかっていない場合はデバイスレコードが作成されます。

今私が抱えている問題は、サーバーがデバイスからの複数のメッセージを処理できる (デバイスからのメッセージごとにスレッドが作成される) ため、競合状態になることです。

だからこれを想像してください:

デバイス A は 2 つのメッセージを次々に送信します。

    Sends hello message              Sends "here is my ip" message
             |                                    |
             |                                    |
             |                                    |
    does not see device in DB                     |
        tries to insert                does not see device in DB
             |                              tries to insert
          Insert completed                        |
                                Failed to insert (Unique key constraints not met)

明らかに、デバイスが 2 回目に挿入されるときに、一意の制約によってエラーが発生します。しかし、最初の挿入が完了すると、Spring はそれを拾い上げて、2 番目のスレッドが再度挿入しようとするときに、挿入する必要がないことを知ることができると考えていました。しかし、さまざまな伝播モードと分離モードを試したにもかかわらず、これは起こりませんでした。非常に基本的なものが欠けているに違いありません。これを修正する方法について正しい方向を教えてください。返信ありがとうございます。必要/要求があれば、より多くの情報を提供します。

4

1 に答える 1

2

これは仕様による動作です。デフォルトでは、コミットされた行のみが表示されます (READ COMMITTED 分離レベル)。コミットされていない行は、外部プロセスのデータベースにまだ存在しないものとして扱うことができます。

最善の解決策は、一意の制約違反をキャッチして再試行することです (理想的には遅延して)。コミットされていない読み取りに分離レベルを下げることもできますが、これにより他の競合状態が発生する可能性があるため、お勧めしません。

于 2013-05-15T01:02:10.920 に答える