Java JPA:PersistenceException,无法更新
我在Java中使用PlayFramework1.2.5,但这更像是一个JPA问题 在我的项目中,我经常通过电子邮件搜索用户,因此我创建了以下方法:Java JPA:PersistenceException,无法更新,java,mysql,jpa,playframework,Java,Mysql,Jpa,Playframework,我在Java中使用PlayFramework1.2.5,但这更像是一个JPA问题 在我的项目中,我经常通过电子邮件搜索用户,因此我创建了以下方法: public static User getUserByEmail(String email) { User user = User.find("email = ?", email).first(); return user; } 我用不同的方法称之为: User user = User.getUserByEmail("test@e
public static User getUserByEmail(String email) {
User user = User.find("email = ?", email).first();
return user;
}
我用不同的方法称之为:
User user = User.getUserByEmail("test@email.com");
当我试图修改用户字段时,如下所示:
User user = User.getUserByEmail("kospol@test.com");
user.name = "kospol";
user.save();
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);
}
我经常遇到以下异常,导致完全冻结:
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方法并直接获取模型。您尝试过显式保存吗 根据,您可以这样做:
User user = User.getUserByEmail("kospol@test.com");
user.name = "kospol";
user.save();
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);
}
也许你必须使用edit()方法(我对这个框架很陌生,不知道是否有效)
希望这有帮助。免责声明:在没有整个项目的情况下回答您的问题并不容易,但这里有两个潜在问题需要调查 我很确定问题不是由方法
getUserByEmail
本身引起的。(特别是因为它有时有效,有时无效)
问题是由另一个非常繁重的查询引起的锁定用户表(或者可能只锁定您搜索的行)很长时间(超过等待超时)
因此,请调查繁重的查询(一种方法是记录所有sql查询,并查看出现异常时正在运行的查询)
另一个选项是死锁(如果您没有看到任何长查询):下面是一个典型的场景
线程1需要锁定表用户和表B。线程2需要锁定表B和表用户
在时间0:
- 线程1接收对用户表的锁定
- 螺纹2在表B上收到锁
- 线程1阻塞并等待表B上的锁
- 线程2阻塞并等待锁定用户表
- 一个线程发生等待锁超时,释放锁并引发异常
- 另一个线程最终接收所需的锁并执行其查询
getUserByEmail
函数
实体类总是完全检入,所以如果要创建
JPA中的一些变量或函数。你必须告诉我发生了什么事
程序必须处理函数或变量。你可以用
注释
在这种情况下,您必须告诉程序忽略该函数。你可以用
@Transient
此批注指定属性或字段不是持久的。它用于注释实体类、映射超类或可嵌入类的属性或字段
在你的情况下,你可以在你的JPA中使用这个
@Transient
public static User getUserByEmail(String email) {
User user = User.find("email = ?", email).first();
return user;
}
这有多大的可复制性?你能创建一个重现问题的模型吗?我知道你给出了一个小代码,但这里的关键是“完整”。我不认为我们可以通过提供的信息帮助你解决这个问题。。。除非您的实体是User,并且您已经在User中定义了所有DB方法,否则为什么不为User上的所有操作创建一个单独的DAO层,看起来您正在调用返回实体上的方法呢?如果这是一个代理呢?