2014-02-17 91 views
2

我想使用版本字段的樂觀鎖定,並且當我從jpa存儲庫調用保存時不會引發異常。我對Spring和冬眠是新手,我擔心我設置不正確。
我使用的庫是: hibernate4 Maven的插件版本1.0.2 休眠-jpa02.0 1.0.1 彈簧數據的JPA版本1.3.4Hibernate樂觀鎖定使用版本不起作用

所以我的實體建立這樣:

@Entity 
public class MyEntity 
{ 
    @Id 
    protected Long id; 

    @Version 
    protected Long version; 

    protected String name; 

    public Long getVersion() 
    { 
     return version; 
    } 

    public void setVersion(Long version) 
    { 
     this.version = version; 
    } 

    public Long getVersion() 
{ 
     return version; 
} 

public void setVersion(Long version) 
    { 
     this.version = version; 
    } 

public Long getId() 
    { 
     return id; 
    } 

public void setId(Long id) 
    { 
     this.id = id; 
    } 

    public String getName() 
    { 
    return name; 
    } 

public void setName(Long id) 
    { 
     this.name = name; 
    } 
} 

我通過我的DTO通過對客戶端傳遞版本,並將它傳遞回來時,我做了保存在我的MyEntityStoreDao:

@Repository 
    public class MyEntityStoreDao extends BaseDao<MyEntityStoreDao> 
    { 

     private RepositoryManager myRepoManager; 

     @Autowired 
     public void setMyRepo(MyEntityRepository myRepo) 
     { 
      this.myRepo = myRepo; 
     } 

     public MyEntity save(MyEntityDTO dtoToUpdate) 
     { 
      Session session = this.Session(); 
      MyEntity myEntity = new MyEntity(); 

      if(dtoToUpdate.getId() > 0) { 
      myEntity = (MyEntity) session.get(MyEntity.class, dtoToUpdate.getId()) 
      }  

      myEntity.setName(dtoToUpdate.getName()); 

      MyEntity result = this.myRepo.save(myEntity); 

      this.repositoryManager.flush(myRepo); 

     } 
    } 

的repositoryManager在BaseDao中,正在使用org.springframework.data.jpa.repository.JpaRepository

版本正在正確更新並正在增加。但是當我進行更新時,我期望從DTO傳遞的版本保存在MyEntityStoreDao中,以便與數據庫中的內容不匹配時,它將引發StaleStateException或OptmisticLockingException。

我檢查和版本不匹配,但保存仍然發生。任何幫助,爲什麼發生這種情況?由於

+1

您的更新代碼在哪裏?如果你正在更新一個對象,請在repo上調用saveOrUpdate(object)方法 – Zeus

+0

你不是自己改變版本嗎?這是JPA提供商應該做的管理工作。測試這種方法的正確方法是創建兩個線程,每個線程同時在自己的唯一事務中獲取並更新同一個實體;其中一個應該在保存時失敗。通過在提交之前在線程中進行幾秒鐘的休眠,這很容易實現。 – Gimby

+0

@Zeus - 更新代碼是jpa存儲庫處理保存的地方。 – Lumpy

回答

0

打開SQL日誌記錄的節目-SQL = TRUE,看看是否更新查詢具有所需的where子句

where version = ? 

如果這樣的where子句缺失,那麼你需要添加註釋@org.hibernate.annotations.Entity(dynamicUpdate = true)

+0

它打印出版本。更新myTable設置版本= ?,名稱=?其中id =?和版本=? dynamicUpdate = true已被棄用。 – Lumpy

+0

只需添加dynamicUpdate = true來驗證它是否正常工作 –

+0

我的確在類的註釋所在的位置添加了myEntity的dynamicUpdate = true。它表示它已被棄用。但它沒有奏效。 @ Entity @ org.hibernate.annotations.Entity(dynamicUpdate = true) public class MyEntity { – Lumpy

0

隨着更新的代碼

MyEntity myEntity = new MyEntity(); // You dont need to initalize 

      if(dtoToUpdate.getId() > 0) { 
      myEntity = (MyEntity) session.get(MyEntity.class, dtoToUpdate.getId()) 
      }  

      myEntity.setName(dtoToUpdate.getName()); 

      MyEntity result = this.myRepo.save(myEntity); 

你要保存的myEntity所,其中有REC來自數據庫的信息(正確版本)。所以你不會得到任何錯誤。如果你想產生錯誤,請執行下列操作..

public MyEntity save(MyEntityDTO dtoToUpdate) 
    { 
     Session session = this.Session(); 
     MyEntity myEntityV1 = null; 
     MyEntity myEntityV2 = null; 

     // Getting v1 and V2. at this time both V1 & V2 will have same version (assume version as 5) 
     if(dtoToUpdate.getId() > 0) { 
     myEntityV1 = (MyEntity) session.get(MyEntity.class, dtoToUpdate.getId()) ; 
     myEntityV2 = (MyEntity) session.get(MyEntity.class, dtoToUpdate.getId()) ; 
     }  

     myEntityV1.setName(dtoToUpdate.getName()); 

     // Saving V1 will reflect the increase in version (actual row will be version of 6) 
     MyEntity result = this.myRepo.save(myEntityV1); 

     myEntityV2.setName("some changes"); // change some in V2instance. So that hibernate/Jpa will capture the change 
     this.myRepo.save(myEntityV2); // You will get exception. because the v2 has version as 5. but the row was updated . 

     this.repositoryManager.flush(myRepo); 

    } 

因此,基本上,當你更新以dB爲單位,如果實體版(對象變量)不等於版本(字段表)在數據庫中(此更新之前)它會拋出異常

+0

我假設代碼是用於測試目的。完全按照你所說的來測試它。創建了2個實體並同時檢索了它們。保存第一個,然後保存第二個,第二個實體保存正確,版本也正確更新。沒有例外被拋出。從您的確切代碼版本只更新一次意味着版本增加一次。如果我在每次保存後添加repoManager.flush,它會增加兩次。所以在你的例子中,使用你的代碼版本只有6,並且名稱「一些變化」在db中。有兩次刷新行,版本是7. – Lumpy

+0

我認爲你沒有修改第一個實體。如果您已經設置了show-sql = true,您是否在查詢中看到過兩個更新?當你有兩次沖洗時,你沒有異常?我確實使用PersistentManagr模擬了這個問題,這個問題在事務註釋中被淘汰,它的工作原理與例外一樣。 – Mani

+0

有兩個更新sql記錄爲兩個實例與一個刷新和2。但是,仍然沒有例外。我不確定爲什麼,現在這讓我感到莫名其妙。感謝您的意見和幫助。 – Lumpy