5

私はのためのサービスを実装しました、entity objectそしてそれは純粋を使用しますjpa、私は使用springしました、それでimplとしてspring xml config構成されました。運用にデータを使用しています。しかし、私たちのシステムでは、オブジェクトが何度もプル/更新されており、データとの競合が高くなっています。多くの場所のコードから、エンティティを取得するためのサービスBeanと呼び出しメソッドだけが多く、その後、エンティティが変更されます(これは私の理解では切り離されていますが、同じスレッドであるため、emオブジェクトは私の知識と同じである必要があります)そのため、エンティティがサービスに戻って更新されるまでしばらく時間がかかり、サービスのメソッドを呼び出してエンティティを保存します。メソッドはただ呼び出すだけですhibernatejpaspringcrudentityconcurrencyclassesinjectgetEntitysave()Save()merge()Crud操作。@Transactional注釈付きのトランザクションです。ここで問題が発生します。誰かがエンティティオブジェクトをプルし、それを変更しているときに他の誰かがそれをプルして変更して保存し直す可能性があるため、エンティティの読み取りがダーティであり、保存すると、すでに更新されたエンティティを上書きします。問題は、サービスの外部でエンティティを変更し、savebackを呼び出すことです。ここで、春のデータリポジトリクラスはDAOレイヤーです。

Optimistic lockは1つの解決策ですが、何らかの理由で気に入らなかったため、機能しません。私は考えていpessimistic lockます。たとえば、ロックして更新するエンティティを取得し、それを別の場所に変更してコールバックすると(entity更新に対してすでにロックされています!)、機能しますか?EntityManagerエンティティをプルするために使用したオブジェクトがまだそこにあるかどうかはわかりません。そこにある場合、更新されてロックが解除される前に、これらの「スマート」ロジックを渡すのに非常に長い時間がかかります。

シナリオの簡単なサンプルコードは次のとおりです。

class SomeEntity {
    Long id;
    String field1;
    String field2;
    String field3;
    String field4;
    String field5;
    String field6;
    String field7;
    //getters and setters, column annotations

}


class SomeEntityServiceImple implemenet SomeEntityService{
      @Transactional
      save(SomeEntity se){
           //call to spring data's merge() method 
      }

      get(Long id){
           //call to spring data's findOne() 
      }

}


//this class might be spring bean, might not be. If it is not I will get SomeEntityService bean from shared appContext
class SomeCrazyClass{
    @Autowired
    SomeEntityService service;
    someMethod(){
       SomeEntity e = service.get(1L);
       //do tons of logic here, change entity object, call some another methods and again, takes 3 seond
      service.save(e); //Probably detached and someone updated this object, probably overriding it.    
    }
}
}

ここでtons of logicは、それをサービスレイヤー内に移動することはできません。これは非常に具体的であり、この種のさまざまなロジックは数百の場所にあります。

それで、回避して、少なくともこの状況に悲観的なロックを適用する方法はありますか?

4

2 に答える 2

3

悲観的ロックの場合、以下のコードを試すことができます

  • エンティティ取得中のロック

    entityManager.find(Entity.class, pk, LockModeType.PESSIMISTIC_WRITE);

  • 後でロックを適用する

    entityManager.lock(entity, LockModeType.PESSIMISTIC_WRITE);

  • クエリでロック モードを設定する

    query.setLockMode(LockModeType.PESSIMISTIC_WRITE);

それ以外の場合は、同期メソッドを に追加してみてくださいSomeEntityServiceImpl

public synchronized void saveEntity(e){
{
Object o = get(id); //-- Fetch most recent entity 
applyChanges(o, e); //-- Applying custom changes
save(o); //-- Persisting entity
}

したがって、すべてのロジックをサービス内に移動する必要はなく、データベース操作のみを委任します。また、アプリケーション ロジックに影響を与えずにコードを変更する一般的な場所になります。

于 2013-02-13T08:16:33.980 に答える
-1

@Transactional アノテーションを上位レイヤーの「SomeCrazyClass」の「someMethod」に移動します。このメソッドで行われた変更は、1 つのトランザクション フローの一部である必要があります。私が知る限り、このフローはアトミックである必要があります。つまり、すべてコミットするか、コミットしない (完全なロールバック) 必要があります。

@Transactional アノテーションを縮退された保存メソッドの上に置くだけでは、このアノテーションのポイントが失われます。そのままにしておくこともできますが (propagation.required のデフォルト値を使用)、1 レベル上にも追加する必要があります。

アプリ全体でこの提案に従う必要があります。ビジネス ロジック メソッドを Transactional アノテーションでラップする必要があることを意味します。

于 2013-02-15T19:35:31.727 に答える