2012-10-15 35 views
1

我試圖更新ProfileEntity我所有的4000點的對象,但我得到以下異常:更新在JPA實體中的所有對象

javax.persistence.QueryTimeoutException: The datastore operation timed out, or the data was temporarily unavailable. 

這是我的代碼:

public synchronized static void setX4all() 
{ 

    em = EMF.get().createEntityManager(); 

    Query query = em.createQuery("SELECT p FROM ProfileEntity p"); 
    List<ProfileEntity> usersList = query.getResultList(); 

    int a,b,x; 
    for (ProfileEntity profileEntity : usersList) 
    { 
     a = profileEntity.getA(); 
     b = profileEntity.getB(); 
     x = func(a,b); 
     profileEntity.setX(x); 

     em.getTransaction().begin();   
     em.persist(profileEntity);   
     em.getTransaction().commit(); 

    } 

    em.close(); 

} 

我m猜測我花了很長時間查詢ProfileEntity的所有記錄。 我該怎麼做?

  • 我正在使用Google App Engine,因此無法更新查詢。

編輯18/10
在這2個日子裏,我嘗試:
使用後端爲薩諾斯Makris建議,但到了一個死衚衕。你可以看到我的問題here
閱讀DataNucleus對Map-Reduce的建議,但真的迷路了。

我正在尋找不同的方向。因爲我只會做這個更新一次,也許我可以手動更新每200個物體左右。
是否有可能查詢前200個對象,然後是第200個對象等等?

+0

您可以發佈完整的堆棧跟蹤? –

+0

然後,我會建議使用任務隊列API來實現此目的。在那裏,通過使用遊標,您將能夠查詢一批實體,更新它們並將它們存儲回去。 –

回答

0

如果要爲所有對象設置(x),最好使用JPA實體管理器的用戶更新語句(即本機SQL),而不是獲取所有對象並逐一更新它。

0

你的類表現得不是很好 - JPA不適合這種批量更新 - 你只是以快速的順序開始大量的事務並且在數據庫上產生大量的負載。爲您的使用情況下更好的解決辦法是標量查詢(具體取決於對象的結構和懶惰,你認爲你會加載更多的數據)

參見Hibernate參考設置的所有對象,而不要將其裝入JVM第一: http://docs.jboss.org/hibernate/orm/3.3/reference/en/html/batch.html#batch-direct

+0

我太抽象了我的問題。我編輯了我的問題,它是否仍然適用於這種情況? – Rami

+0

你只是加載太多的數據到您的EM - 考慮將此更新完全移到後端,也許發佈完整的堆棧跟蹤來查看哪些查詢冒犯了GAE –

+0

我添加了完整的堆棧跟蹤。 – Rami

2

鑑於你的情況,我會建議運行一個本地更新查詢:

Query query = em.createNativeQuery("update ProfileEntity pe set pe.X = 'x'"); 
query.executeUpdate(); 

請注意:這裏的查詢字符串SQLupdate **table_name** set ....

這會更好。

+0

我抽象了太多的問題。我編輯了我的問題,它是否仍然適用於這種情況? – Rami

+0

是你的函數Java函數嗎?如果是的話,DB中有沒有寫同樣的東西?如果你可以移動/複製數據庫中的函數,你可以很好地做到這一點,查詢是 - 「更新ProfileEntity pe pe.pe.X = func(pe.a,pe.b)'。 –

+0

是的功能是在Java中。你是什​​麼意思移動/複製數據庫中的功能?我試着按你寫的做,現在我得到javax.persistence.PersistenceException:不支持批量更新語句。 – Rami

1

將更新過程更改爲使用類似Map-Reduce的東西。這意味着全部都在數據存儲中完成。唯一的問題是,appengine-mapreduce還沒有完全發佈(儘管你可以自己輕鬆構建jar並在GAE應用程序中使用它 - 許多其他人都這麼做)。

0

也許你應該考慮使用Task Queue API,使你能夠執行任務最多10分鐘。如果您想更新任務隊列不適合您的實體數量,您還可以考慮使用Backends

0

把交易的循環之外:

em.getTransaction().begin();   
for (ProfileEntity profileEntity : usersList) { 
... 
} 
em.getTransaction().commit();