我已經爲我的應用程序編寫了一個測試用例,以查看交易的行爲。而且我發現沒有任何事情按照我認爲的方式工作。JPA和Spring交易 - 請現在解釋
我有一個基於Spring的應用程序,使用Hibernate作爲JPA提供程序,由MySQL支持。 我有DAO對象,擴展了Spring的JpaDaoSupport。 Spring的事務管理涵蓋了這些內容。
我創建這樣作品測試用例: 1)實體被創建,一些計數器設置爲0。 2)然後兩個線程被創建,其中兩個在一個調用DAO方法incrementCounter()循環。我認爲,當事務覆蓋DAO方法時,只有一個線程會在其中(即,Spring將負責同步)。但這已被證明是錯誤的假設。
在(臨時的)通過將添加到DAO方法之後,我發現Hibernate不存儲DAO方法所做的更改,而另一個線程在find()實體時具有舊數據。只有明確的電話this.getJpaTemplate().flush();
幫助。
我也認爲實體管理器會從持久化上下文的緩存中給我同樣的實體實例,但這也是錯誤的。我已經檢查了hashCode()和equals(),它們都很好 - 基於實體的bussines關鍵字。
歡迎任何評論,因爲它似乎我錯過了JPA/Spring如何處理事務的一些基本概念。
- DAO方法應該是?
- 我應該在每個DAO方法結束時調用flush()嗎?
- Spring是否負責使DAO方法的調用具有事務性? (即不讓兩個線程同時在同一個實體中工作)
- 如果不是,我該如何實現這個目標?
請注意,在我的測試用例中,我使用了一個單獨的DAO對象,但是應該可以,因爲Spring的bean是單例 - 對嗎?
感謝您的任何幫助。
public class EntityDaoImpl extends JpaDaoSupport implements EntityDao {
public synchronized void incrementCounter(String znacka)
{
String threadName = Thread.currentThread().getName();
log.info(threadName + " entering do incrementCounter().");
Entity ent = this.getJpaTemplate().find(Entity.class, znacka);
log.info("Found an entity "+ent.getZnacka()+"/"+ent.hashCode()+" - " + ObjectUtils.identityToString(ent));
log.info(threadName + ": Actual count: "+ent.getCount());
ent.setCount(ent.getCount() + 5);
int sleepTime = threadName.endsWith("A") ? 700 : 50;
try { Thread.sleep(sleepTime); }
catch(InterruptedException ex) { }
ent.setCount(ent.getCount() + 5);
this.getJpaTemplate().flush();
log.info(threadName + " leaving incrementCounter().");
}
}
沒有和flush()
,這是給我像輸出
Thread A: Actual count: 220
...
Thread B: Actual count: 220
...
Thread A: Actual count: 240
...
Thread B: Actual count: 250
...
Thread A: Actual count: 250
...等等,這意味着一個線程自動覆蓋從其他的變化。
感謝您的回答。 我開始將用例放到DAO中,因爲在JpaDaoSupport中,DAO對象只是一個用於將引用轉換爲正確類型的瘦shell。如果我理解得很好,用另一層用例,我最終將得到其他Spring管理的bean,實現用例,用Spring事務而不是DAO來執行AOP;所以它在技術上是相同的,不是嗎? 你會推薦什麼方法來照顧同步? 你會推薦一些Spring 2.5 + JPA教程應用程序嗎?謝謝 – 2009-08-24 00:38:21
我已經引用了Spring的成語 - 我建議遵循它,特別是如果這是你第一次與Spring。通常我在Java EE應用服務器(如Tomcat或JBOSS或WebLogic)上運行Spring,因此每個請求都在其自己的線程中運行。應用程序服務器將處理請求排隊。我會推薦Spring參考文檔。 – duffymo 2009-08-24 00:45:06
那麼,我所做的是在Tomcat上運行的Web應用程序的後端。 Spring引用是好的和廣泛的,但仍然不包含同步提示 - 至少我沒有找到。 我猜EntityManager#鎖(對象實體,LockModeType lockMode)是我應該看看,對吧? – 2009-08-24 01:03:59