java JPA EntityManager:merge() 试图在数据库中创建一个新行 - 为什么?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/4889730/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
JPA EntityManager: merge() is trying to create a new row in the db - why?
提问by sanity
I'm using JPA through the Play Framework.
我正在通过 Play 框架使用 JPA。
I'm checking to see if a User object is cached, and if so I retrieve it and merge() it such that I can update fields and save the changes later:
我正在检查 User 对象是否被缓存,如果是,我检索它并合并()它以便我可以更新字段并稍后保存更改:
user = (User) Cache.get("user-auth-" + sessionAuthToken);
if (user != null) {
user = user.merge(); // I believe this is the same as EntityManager.merge()
}
However when I do this I get the following error:
但是,当我这样做时,我收到以下错误:
PersistenceException occured :
org.hibernate.exception.ConstraintViolationException:
could not insert: [models.User]
...
Caused by: com.mysql.jdbc.exceptions.jdbc4.
MySQLIntegrityConstraintViolationException:
Duplicate entry '1235411688335416533' for key 'authToken'
It seems like its trying to insert a new user, even though this user should be, and is already in the database. Why would merge() do that?
似乎它试图插入一个新用户,即使这个用户应该是,并且已经在数据库中。为什么要合并()这样做?
Or perhaps I'm going about this entirely the wrong way - advice would be appreciated.
或者我可能完全以错误的方式处理这个问题 - 建议将不胜感激。
采纳答案by Pere Villega
I believe your problem is the way Play manages the JPA environment (and transactions).
我相信您的问题是 Play 管理 JPA 环境(和事务)的方式。
Once you receive a request the framework immediately creates the JPA manager and a transaction. From that moment onwards all your Model entities are automatically linked to the manager.
一旦您收到请求,该框架会立即创建 JPA 管理器和一个事务。从那一刻起,您的所有模型实体都会自动链接到管理器。
Play facilitates working with this model in 2 ways:
Play 以两种方式促进了使用此模型的工作:
- You have to explicitly indicate that you want to save changes to an object (via save())
- Transaction is committed automatically unless there is an exception or you flag it for rollback (JPA.setRollbackOnly())
- 您必须明确指出要保存对对象的更改(通过 save())
- 除非有异常或您将其标记为回滚,否则事务将自动提交 (JPA.setRollbackOnly())
By running "merge" you are trying to add to the Manager an entity which is already there, which causes the unique key exception. If you just load the entity from the cache, you will be able to modify and call save() once done, and it will work.
通过运行“合并”,您试图向管理器添加一个已经存在的实体,这会导致唯一键异常。如果您只是从缓存中加载实体,您将能够在完成后修改和调用 save() ,它会起作用。
回答by Christian Kuetbach
I think it may be a poblem with hashCode()
and equals()
. If there are not implemented correctly, a new entity my be inserted instead of updateing an existing one.
我认为这可能是hashCode()
和 的问题equals()
。如果没有正确实现,可能会插入一个新实体而不是更新现有实体。
回答by Thomas W
It's an entity definition problem; specifically with regard to primary key/ unsaved values.
这是一个实体定义问题;特别是关于主键/未保存的值。
The entity definition needs to be correct, for Hibernate to recognize it as 'already saved'. For example, having 'null' in a nullable version field can cause Hibernate to disregard any existing ID & regard it as unsaved.
实体定义需要正确,以便 Hibernate 将其识别为“已保存”。例如,在可空版本字段中包含“null”会导致 Hibernate 忽略任何现有 ID 并将其视为未保存。
This is a Hibernate question, not just JPA. JPA is the interface -- you're having trouble with a specific implementation.
这是一个 Hibernate 问题,而不仅仅是 JPA。JPA 是接口——您在使用特定实现时遇到问题。
回答by Alexander Torstling
See What is the proper way to re-attach detached objects in Hibernate?. Merge tries to write the stale state to the db in order to overwrite possible other concurrent updates. The linked question mentions session.lock(entity, LockMode.NONE);
as a possible solution, I haven't tried it though.
请参阅在 Hibernate 中重新附加分离对象的正确方法是什么?. 合并尝试将陈旧状态写入数据库,以覆盖可能的其他并发更新。链接的问题提到session.lock(entity, LockMode.NONE);
了一个可能的解决方案,但我还没有尝试过。
回答by axtavt
If authToken
is not a primary key, then perhaps primary key of the User
instance being merged doesn't match the primary key of its counterpart in the database, therefore merge()
thinks that it's a new User
and tries to insert it.
如果authToken
不是主键,则可能User
正在合并的实例的主键与其在数据库中对应的主键不匹配,因此merge()
认为它是一个新的User
并尝试插入它。
So, check the primary key of the User
, perhaps it have been corrupted or lost somehow.
因此,请检查 的主键User
,可能它已以某种方式损坏或丢失。