2017-05-03 27 views
0

Java 8、Hibernate 5.1.0.Final、Guice 4.1.0、Jersey 1.19を使用します。私はデータベースからロードされた同じオブジェクトエンティティを変更するいくつかのRESTメソッドを持っています。彼らは同時に実行し、同じ項目を変更すると、私が手:異なるRESTメソッドが同じオブジェクトを変更します - RollbackException、OptimisticLockException、StaleStateException

javax.persistence.RollbackException: Error while committing the transaction 
    at org.hibernate.jpa.internal.TransactionImpl.commit(TransactionImpl.java:86) 

Caused by: javax.persistence.OptimisticLockException: Batch update returned unexpected row count from update [0]; actual row count: 0; expected: 1 

Caused by: org.hibernate.StaleStateException: Batch update returned unexpected row count from update [0]; actual row count: 0; expected: 1 

考えられる解決策:

  • は常にOptimisticLockExceptionの機会を低減するために、オブジェクトの状態を更新するREST方式でのオブジェクトによって

    その他のオプションはありますか?この問題を処理する最善の方法は何ですか?

    public void changeItemName(Long id, String name){ 
    
        Item item = itemDAO.find(id); 
        item.setName(name); 
    
        try { 
         itemDAO.save(item); 
        } catch (RollbackException | OptimisticLockException | StaleStateException e) { 
         logger.warn("Retry method after " + e.getClass().getName()); 
         changeItemName(id, name); 
        } 
    } 
    

    しかし、私は得る:REST方式で

    オブジェクトによって
    javax.persistence.RollbackException: Error while committing the transaction 
    at org.hibernate.jpa.internal.TransactionImpl.commit(TransactionImpl.java:86) 
    
    Caused by: javax.persistence.PersistenceException: org.hibernate.exception.GenericJDBCException: could not update: [com.example.Item#1] 
    at org.hibernate.jpa.spi.AbstractEntityManagerImpl.convert(AbstractEntityManagerImpl.java:1692) 
    
    Caused by: org.hibernate.exception.GenericJDBCException: could not update: [com.example.Item#1] 
    at org.hibernate.exception.internal.StandardSQLExceptionConverter.convert(StandardSQLExceptionConverter.java:47) 
    
    Caused by: org.postgresql.util.PSQLException: This statement has been closed. 
    at org.postgresql.jdbc2.AbstractJdbc2Statement.checkClosed(AbstractJdbc2Statement.java:2653) 
    
  • 答えて

    1
    1. 同期私は考え、私は実装再試行しようとした

      UPDATE 1

      それは不可能だと言います。 2つのノードで同じサービスが実行されているとします。

    2. オブジェクトステータスを常にリフレッシュするは、オプションではありません。更新はちょうど2リフレッシュの間に起こる可能性があります。

    3. これは問題ありません。 CASの原理。バージョンが正しくない間に変更を保存してください。しかし実際それはあなたのビジネスロジックに依存します。例えば。 Userオブジェクトがあり、初期名は "name1"でした。最初の呼び出しは、それを "name1"から "name2"に変更します。 2番目の呼び出しは、 "name1"から "name3"に変更しようとします。 (A) "name1" - > "name2"更新を抑制する名前を変更するか、または(B)実際の状態を表示して変更を実際の状態に適用するために、呼び出し側に報告する変更を拒否することができます。

    口座残高(A)のアプローチは有効ではなく、(B)が必要です。

    必要なビジネスロジックに従って何をすべきかを決定する必要があります。

    更新: このようには動作しません。トランザクションを開始し、別のトランザクションでトランザクションを開始する場合は、それを高くする必要があります。

    あなたは楽観的ロック例外が発生する可能性が

    @Service 
    public class MyServiceImpl 
        @Transactional 
        public void changeItemName(Long id, String name) { 
        } 
    

    があるとします。 メソッドをcatchからブロックすると、プロキシメソッドが呼び出されないため、新しいトランザクションが開始されません。

    この

    @Service 
    public class MyServiceImpl 
        @Autowired 
        private MyService myService; 
        @Transactional 
        public void changeItemName(Long id, String name) { 
         catch() { 
         myService.changeItemName(id, name); 
         } 
        } 
    
    +0

    はlibにhttps://vladmihalcea.com/2013/11/15/optimistic-locking-retry-with-jpa/で再試行しようとしましたが、それはdidnのようにする代わりに、あなたが何かを行うことができます仕事はありません。さて、例外のtry-catchを追加してメソッドを再試行しましたが、別の問題に直面しました。再試行したときにオブジェクトがキャッシュから取得され、バージョンがリフレッシュされず、無限ループになります。 – Justas

    +0

    再試行する前にリフレッシュ、マージ、エビクト、クリアを試みましたが、助けにはなりませんでした。 – Justas

    +0

    私はあなたが例外をキャッチする必要があると思います(私はそれが動作するはずだと思います)オブジェクトをもう一度(entityManager.refresh(エンティティ))を取得し、変更を適用し、保存します。何とかバージョンをコピーしないことを確認してください。 – StanislavL

    関連する問題