2014-03-12 41 views
0

我在服務類中有以下代碼。作爲功​​能的一部分,此代碼從兩種不同的方法中調用兩次。Hibernate給org.hibernate.NonUniqueObjectException並將過時的對象保存到數據庫

 //Some code here... 
     LOG.info("###Inside customer interceptor"); 
     try 
     { 
      customerDao.save(customer); 

     } 
     catch (final Exception exp) 
     { 
     //some code here too... 
     } 

當它從第一個方法調用和執行第一次,我可以看到,有在Tomcat的控制檯打印的選擇SQL語句,但沒有更新SQL語句,如我所料(可能是因爲事實上,Hibernate不會立即發佈插入/更新)。 立即當從第二個方法再次調用這個代碼塊時,我看到一個SQL select語句,然後在tomcat控制檯中看到一條SQL update語句,之後我立即看到一個大胖子org.hibernate.NonUniqueObjectException。 這是我可以理解的,因爲先前的實體仍然附加到會話並且沒有提交給DB。

但是,當我去看看數據庫時,我發現保存在數據庫中的值是第一次調用的對象,而不是我預期的第二次調用的對象。這是正常的還是我在這裏錯過了一些東西?

我使用Spring的註解(@Transactional)驅動的事務策略。

回答

1

我寧可使用.merge(customer)方法或.saveOrUpdate(customer)方法來執行此操作。

  • 如果您使用.merge,您將不會得到nonUnique異常,因爲它會覆蓋與剛剛傳遞的會話中的對象。
  • 在何處執行saveOrUpdate時,會話不應該有 您要更新的對象的相同實例,否則您會得到此nonUniqueObject異常。

因爲您使用的是Spring @Transactional,所以應在完成方法執行後提交事務。

+0

謝謝宙斯。是的,爲了測試目的,我嘗試使用merge()作爲其他帖子的建議,它確實保存了新的對象而不是過時的,並且我沒有得到nonUniqueObject異常。然而,我的問題更多的是要理解爲什麼儘管在方法級使用@Transactional,爲什麼它在方法執行結束後沒有提交,其次爲什麼在調用save方法而不是當前的過時對象被保存在數據存儲中。 –

+0

我可能需要了解打電話是如何回答你的問題的。如果使用同一個會話來更新兩個具有相同ID的客戶對象,那麼您將得到該異常非唯一異常。在你的代碼的某個地方,會話沒有關閉,所以你第一次保存,沒有錯誤,第二次它會給出錯誤,因爲會話已經有了這個對象。另外,保存用於存儲瞬態對象而不是分離對象。 – Zeus

+0

嗯......我在Hybris電子商務平臺內部使​​用了這段代碼,而且這段代碼在Interceptor類內部,每當與這個攔截器相關的模型發生任何變化時都會觸發它。當然,我正在使用googlecode實現hibernate,其中save()正好完成saveOrUpdate()在其他Hibernate實現中的作用。 –

相關問題