簡體   English   中英

JPA merge()最佳實踐

[英]JPA merge() best practice

我為entity object實現了一個服務,它使用了純jpa ,我使用了spring ,所以在spring xml config配置hibernate作為jpa impl。 我正在使用spring數據進行crud操作。 但是在我們的系統中,我們的entity對象被多次拉取/更新 ,並且數據存在高度爭用( concurrency )。 從許多地方的代碼中,許多classesinject服務bean並調用getEntity方法來獲取實體,之后它們更改實體(根據我的理解分離,但在同一個線程中,因此em對象應該與per相同)我的知識)所以實體需要一段時間才能恢復服務,他們調用服務的save()方法來保存實體。 Save()方法只是調用merge() crud操作。 它與@Transactional注釋是事務性的。 這是一個問題,當有人拉實體對象並在更改它時,其他人可能會拉動並更改它並將其保存回來,所以我的實體讀取是臟的,如果保存它,我將覆蓋已經更新的實體。 問題是我們在服務之外更改實體並調用save。 這里spring數據存儲庫類是DAO層。

Optimistic lock是一種解決方案,但由於某些原因我們不喜歡它,所以它對我們不起作用。 我在考慮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 ,它是非常具體的,這種不同的邏輯在100多個地方。

那么有沒有辦法繞過這種情況並至少應用悲觀鎖定?

對於悲觀鎖定,您可以嘗試以下代碼

  • 獲取實體時鎖定

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

  • 之后應用鎖定

    entityManager.lock(entity, LockModeType.PESSIMISTIC_WRITE);

  • 在查詢中設置鎖定模式

    query.setLockMode(LockModeType.PESSIMISTIC_WRITE);

否則,您可以嘗試在SomeEntityServiceImpl添加synchronized方法。

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

因此,您不必在服務中移動所有邏輯,而只需委派數據庫操作。 此外,它將是代碼更改的常見位置,而不會影響應用程序邏輯。

將@Transactional注釋移動到上層到“SomeCrazyClass”的“someMethod”。 使用此方法所做的更改必須是一個事務流的一部分。 據我所知,這個流應該是原子的,這意味着它應該全部被提交或者不被提交(完全回滾)。

將@Transactional注釋單獨放在退化的保存方法之上是缺少此注釋的要點。 您仍然可以將其保留在那里(使用propagation.required默認值),但您確定需要將其添加到一級。

您應該在整個應用中遵循此建議。 這意味着您應該使用Transactional注釋包裝業務邏輯方法。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM