2013-07-31 42 views
0

我使用Java的Play Framework 1.2.5,但這更多的是JPA問題。JPA:PersistenceException,無法更新

在項目中,我經常被他們的電子郵件進行搜索的用戶,所以我創建了以下方法:

public static User getUserByEmail(String email) { 
    User user = User.find("email = ?", email).first(); 
    return user; 
} 

,我這樣稱呼它從不同的方法:

User user = User.getUserByEmail("[email protected]"); 

當我試圖修改這樣的用戶字段:

User user = User.getUserByEmail("[email protected]"); 
user.name = "kospol"; 
user.save(); 

我經常會得到以下異常,導致我n總凍結數:

Execution exception (In /app/controllers/*******.java around line 46) 
PersistenceException occured : update User set activated=?, ... registered=?,  registeredFrom=?, version=? where id=? and version=? 


play.exceptions.JavaExecutionException: update User set activated=?, ... registered=?,  registeredFrom=?, version=? where id=? and version=? 
    at play.mvc.ActionInvoker.invoke(ActionInvoker.java:237) 
    at Invocation.HTTP Request(Play!) 
Caused by: javax.persistence.PersistenceException: update User set activated=?, ... registered=?, registeredFrom=?, version=? where id=? and version=? 
    at play.db.jpa.JPABase._save(JPABase.java:44) 
    at play.db.jpa.GenericModel.save(GenericModel.java:204) 
    at controllers.PushService.register(PushService.java:46) 
    at play.mvc.ActionInvoker.invokeWithContinuation(ActionInvoker.java:557) 
    at play.mvc.ActionInvoker.invoke(ActionInvoker.java:508) 
    at play.mvc.ActionInvoker.invokeControllerMethod(ActionInvoker.java:484) 
    at play.mvc.ActionInvoker.invokeControllerMethod(ActionInvoker.java:479) 
    at play.mvc.ActionInvoker.invoke(ActionInvoker.java:161) 
    ... 1 more 
Caused by: javax.persistence.PersistenceException: org.hibernate.exception.GenericJDBCException: could not update: [models.User#3606] 
    at org.hibernate.ejb.AbstractEntityManagerImpl.convert(AbstractEntityManagerImpl.java:1389) 
    at org.hibernate.ejb.AbstractEntityManagerImpl.convert(AbstractEntityManagerImpl.java:1317) 
    at org.hibernate.ejb.AbstractEntityManagerImpl.convert(AbstractEntityManagerImpl.java:1323) 
    at org.hibernate.ejb.AbstractEntityManagerImpl.flush(AbstractEntityManagerImpl.java:965) 
    at play.db.jpa.JPABase._save(JPABase.java:41) 
    ... 8 more 
Caused by: org.hibernate.exception.GenericJDBCException: could not update: [models.User#3606] 
    at org.hibernate.exception.SQLStateConverter.handledNonSpecificException(SQLStateConverter.java:140) 
    at org.hibernate.exception.SQLStateConverter.convert(SQLStateConverter.java:128) 
    at org.hibernate.exception.JDBCExceptionHelper.convert(JDBCExceptionHelper.java:66) 
    at org.hibernate.persister.entity.AbstractEntityPersister.update(AbstractEntityPersister.java:2613) 
    at org.hibernate.persister.entity.AbstractEntityPersister.updateOrInsert(AbstractEntityPersister.java:2495) 
    at org.hibernate.persister.entity.AbstractEntityPersister.update(AbstractEntityPersister.java:2822) 
    at org.hibernate.action.EntityUpdateAction.execute(EntityUpdateAction.java:113) 
    at org.hibernate.engine.ActionQueue.execute(ActionQueue.java:273) 
    at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:265) 
    at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:185) 
    at org.hibernate.event.def.AbstractFlushingEventListener.performExecutions(AbstractFlushingEventListener.java:345) 
    at org.hibernate.event.def.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:51) 
    at org.hibernate.impl.SessionImpl.flush(SessionImpl.java:1216) 
    at org.hibernate.ejb.AbstractEntityManagerImpl.flush(AbstractEntityManagerImpl.java:962) 
    ... 9 more 
Caused by: java.sql.SQLException: Lock wait timeout exceeded; try restarting transaction 
    at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:1073) 
    at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:4096) 
    at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:4028) 
    at com.mysql.jdbc.MysqlIO.sendCommand(MysqlIO.java:2490) 
    at com.mysql.jdbc.MysqlIO.sqlQueryDirect(MysqlIO.java:2651) 
    at com.mysql.jdbc.ConnectionImpl.execSQL(ConnectionImpl.java:2683) 
    at com.mysql.jdbc.PreparedStatement.executeInternal(PreparedStatement.java:2144) 
    at com.mysql.jdbc.PreparedStatement.executeUpdate(PreparedStatement.java:2444) 
    at com.mysql.jdbc.PreparedStatement.executeUpdate(PreparedStatement.java:2362) 
    at com.mysql.jdbc.PreparedStatement.executeUpdate(PreparedStatement.java:2347) 
    at org.hibernate.persister.entity.AbstractEntityPersister.update(AbstractEntityPersister.java:2595) 
    ... 19 more 

我已將@Version註釋添加到模型中。看來問題是超出鎖定等待超時時間。我怎樣才能避免這種情況?

我試圖使用沒有結果的.merge()方法,我想刪除getUserByEmail方法並直接獲取模型。

+0

如何重現的是這個使用這個

在你的情況下?你可以創建一個能重現問題的[sscce](http://sscce.org)嗎?我知道你給了一些代碼,但這裏的關鍵是「完整的」。我不認爲我們可以幫助您找出所提供的信息...除非[這是答案](http://stackoverflow.com/questions/13966467/how-to-avoid-lock-wait- timeout-exceeded-exception) – durron597

+0

您的實體是用戶,您已經定義了用戶中的所有數據庫方法,爲什麼不爲用戶上的所有操作創建單獨的DAO層,看起來像您正在調用返回實體上的方法,如果這是一個代理 ? –

回答

0

你試過顯式保存嗎?

Play framework persistence docs根據你可以做這樣的事情:

public static void save(Long id) { 
    User user = User.findById(id); 
    user.edit(params); 
    validation.valid(user); 

    if(validation.hasErrors()) { 
     // Here we have to explicitly discard the user modifications... 
     user.refresh(); 
     edit(id); 
    } 
    show(id); 
} 

也許你必須使用編輯()方法(我很新打框架,不知道是不是作品)。

希望這會有所幫助。

1

聲明:在沒有整個項目的情況下回答您的問題並不容易,但這裏有兩個潛在的問題需要調查。

我很確定問題不是由方法getUserByEmail本身造成的。 (尤其是因爲它有時可用,有時不適用)。

問題是由另一非常沉重查詢引起鎖定用戶表(或也​​許只有該行的尋訪)很長一段時間(超過等待超時)。

因此,調查沉重的查詢(一種方法是記錄所有sql查詢並查看在發生異常時正在運行的查詢)。

另一種選擇是死鎖(如果您沒有看到任何長查詢):這是一個典型的情況。

線程1需要鎖表用戶和表B.線程2需要鎖表B和表用戶。

在時間0:

  • 線程1接收關於表用戶的鎖定
  • 螺紋2接收上表B中

鎖定在時間1:

  • 螺紋1塊並等待表B上的鎖定
  • 線程2塊和wa這對錶用戶

鎖定在時間2:發生了一個線程

  • 等待鎖超時,鎖被釋放,並且拋出異常。

在時間3:

  • 其他線程收到最後所需的鎖並執行它的查詢。
0

如果我在正確的軌道這是你面臨的問題..!

問題是您在JPA內部添加了getUserByEmail函數。

實體類始終處於全檢查,所以如果你想創建JPA內 一些變量或函數。您必須告訴程序必須對函數或變量做些什麼。爲此,您可以使用 註釋

在您的情況下,您必須告訴程序忽略該功能。爲此,您可以使用

@Transient 

此註釋指定屬性或字段不是永久的。它用於註釋實體類,映射超類或可嵌入類的屬性或字段。你可以在你的JPA

@Transient 
public static User getUserByEmail(String email) { 
    User user = User.find("email = ?", email).first(); 
    return user; 
}