休眠错误:org.hibernate.NonUniqueObjectException:具有相同标识符值的不同对象已与会话关联
Posted
技术标签:
【中文标题】休眠错误:org.hibernate.NonUniqueObjectException:具有相同标识符值的不同对象已与会话关联【英文标题】:Hibernate Error: org.hibernate.NonUniqueObjectException: a different object with the same identifier value was already associated with the session 【发布时间】:2010-11-07 15:03:41 【问题描述】:我有两个用户对象,当我尝试使用
保存对象时session.save(userObj);
我收到以下错误:
Caused by: org.hibernate.NonUniqueObjectException: a different object with the same identifier value was already associated with the session:
[com.pojo.rtrequests.User#com.pojo.rtrequests.User@d079b40b]
我正在使用
创建会话BaseHibernateDAO dao = new BaseHibernateDAO();
rtsession = dao.getSession(userData.getRegion(),
BaseHibernateDAO.RTREQUESTS_DATABASE_NAME);
rttrans = rtsession.beginTransaction();
rttrans.begin();
rtsession.save(userObj1);
rtsession.save(userObj2);
rtsession.flush();
rttrans.commit();
rtsession.close(); // in finally block
我还尝试在保存之前执行session.clear()
,但仍然没有运气。
这是我第一次在用户请求到来时获取会话对象,所以我知道为什么说该对象存在于会话中。
有什么建议吗?
【问题讨论】:
这是另一个很棒的帖子,它帮助解决了我的问题getj2ee.over-blog.com/… 【参考方案1】:我已经多次遇到这个错误,而且很难追查...
基本上,hibernate 的意思是你有两个对象具有相同的标识符(相同的主键),但它们不是同一个对象。
我建议你分解你的代码,即注释掉一些位直到错误消失,然后把代码放回去,直到它回来,你应该找到错误。
它通常通过级联保存发生,其中对象 A 和 B 之间存在级联保存,但对象 B 已与会话关联,但与 A 上的对象不在同一个 B 实例上。
您使用的是什么主键生成器?
我问的原因是这个错误与你如何告诉 hibernate 确定对象的持久状态(即对象是否持久)有关。该错误可能会发生,因为 hibernate 正在尝试持久化一个已经持久化的对象。事实上,如果你使用 save hibernate 会尝试并持久化该对象,并且可能已经有一个具有与会话关联的相同主键的对象。
示例
假设您有一个基于主键组合(第 1 列和第 2 列)的包含 10 行的表的休眠类对象。现在,您在某个时间点从表中删除了 5 行。现在,如果您尝试再次添加相同的 10 行,而 hibernate 尝试将对象持久保存在数据库中,则将添加已删除的 5 行而不会出错。现在剩下的 5 行已经存在,将抛出这个异常。
因此,简单的方法是检查您是否更新/删除了表中的任何值,该值是某些内容的一部分,然后您是否尝试再次插入相同的对象
【讨论】:
不错的答案²。主键是我的问题,通过 GeneratedValue 为 postgresql 设置序列来解决。 我遇到了同样的问题。在我的例子中,我在代码中搜索了一个对象,并尝试在其他代码段中构建一个具有相同 ID 的新对象,而第一个对象尚未处于休眠状态。 这个问题困扰了我几天。I would suggest you break down your code
这绝对是最好的答案。玩转流程。更改 CascadeTypes。至于我,有效的是订单。最初我所做的是在父母之前删除孩子。对我有用的是在孩子之前删除父母。这很奇怪,但它奏效了。因此,只需上下播放代码,直到获得理想的结果。 Hibernate 关系肯定很奇怪。【参考方案2】:
这只是hibernate产生的问题多于解决的问题的一点。 在我的例子中,有许多具有相同标识符 0 的对象,因为它们是新的并且没有。 db 生成它们。在某处我读到 0 信号 Id 未设置。持久化它们的直观方法是遍历它们并说休眠以保存对象。但是你不能那样做——“当然你应该知道hibernate是这样那样工作的,因此你必须……” 所以现在我可以尝试将 Ids 更改为 Long 而不是 long 并查看它是否有效。 最后,您自己使用简单的映射器会更容易,因为休眠只是一个额外的不透明负担。 另一个例子:试图从一个数据库中读取参数并将它们保存在另一个数据库中,这迫使您几乎手动完成所有工作。但是,如果您无论如何都必须这样做,那么使用休眠只是额外的工作。
【讨论】:
我也讨厌hibernate...和数据库...毕竟它们给我带来的所有问题我想使用文本文件更容易(我在开玩笑,但仍然...)。 在我的例子中,有许多具有相同标识符 0 的对象,因为它们是新的并且没有。 db 生成它们。在某处我读到 0 信号 Id 未设置。持久化它们的直观方法是遍历它们并说休眠以保存对象。我需要这样做。你能告诉我这是什么“休眠方式”吗? 在我的情况下,我不得不使用 session.merge(myobject) 因为我有这个对象的两个实例。通常当实体被持久化并与会话分离时会发生这种情况。该实体的另一个实例被请求休眠。第二个实例保持连接到会话。第一个实例被修改。更多getj2ee.over-blog.com/… 这不是hibernate制造问题,而是缺乏了解它是如何工作的【参考方案3】:使用session.evict(object);
evict()
方法的功能用于从会话缓存中删除实例。所以第一次保存对象时,在从缓存中驱逐对象之前调用session.save(object)
方法保存对象。以同样的方式在调用 evict() 之前调用 session.saveOrUpdate(object)
或 session.update(object)
更新对象。
【讨论】:
【参考方案4】:当您使用相同的会话对象进行读写时,可能会发生这种情况。如何? 假设您创建了一个会话。 您使用主键 Emp_id=101 从员工表中读取记录 现在您已经在 Java 中修改了记录。 您将把员工记录保存在数据库中。 我们在这里的任何地方都没有结束会议。 由于被读取的对象也保留在会话中。它与我们希望写入的对象冲突。因此出现了这个错误。
【讨论】:
【参考方案5】:正如上面已经指出的那样,当我在one-to-many
关系的两端都有cascade=all
时遇到了这个问题,所以让我们假设 A --> B(来自 A 的一对多和多对-一个来自 B) 并在 A 中更新 B 的实例,然后调用 saveOrUpdate(A) ,它导致循环保存请求,即 A 的保存触发 B 的保存,触发 A 的保存...并且在第三个实例中为试图将实体(的 A)添加到 sessionPersistenceContext 引发了重复对象异常。 我可以通过从一端移除级联来解决它。
【讨论】:
和***.com/questions/4334970/…一起解决了我的问题【参考方案6】:您可以使用session.merge(obj)
,如果您正在使用具有相同标识符的持久对象的不同会话进行保存。
成功了,我之前也遇到过同样的问题。
【讨论】:
【参考方案7】:我遇到了这个问题:
-
删除对象(使用 HQL)
立即存储具有相同 id 的新对象
我通过在删除后刷新结果并在保存新对象之前清除缓存来解决它
String delQuery = "DELETE FROM OasisNode";
session.createQuery( delQuery ).executeUpdate();
session.flush();
session.clear();
【讨论】:
【参考方案8】:我也遇到了这个问题,很难找到错误。
我遇到的问题如下:
该对象已被具有不同休眠会话的 Dao 读取。
为避免此异常,只需使用稍后将保存/更新此对象的 dao 重新读取该对象。
所以:
class A
readFoo()
someDaoA.read(myBadAssObject); //Different Session than in class B
class B
saveFoo()
someDaoB.read(myBadAssObjectAgain); //Different Session than in class A
[...]
myBadAssObjectAgain.fooValue = 'bar';
persist();
希望能为一些人节省很多时间!
【讨论】:
【参考方案9】:当我们更新相同的会话对象时会出现此问题,我们曾使用该对象从数据库中获取对象。
你可以使用hibernate的merge方法代替update方法。
例如首先使用 session.get(),然后你可以使用 session.merge(object)。这种方法不会产生任何问题。我们也可以使用 merge() 方法来更新数据库中的对象。
【讨论】:
【参考方案10】:获取会话内的对象,这里是一个例子:
MyObject ob = null;
ob = (MyObject) session.get(MyObject.class, id);
【讨论】:
不错的尝试,但返回的对象“ob”没有更新数据(考虑到它是在运行时通过应用程序更新的,在从数据库检索的对象和保存之间)。【参考方案11】:默认情况下使用身份策略,但我通过添加来修复它
@ID
@GeneratedValue(strategy = GenerationType.IDENTITY)
【讨论】:
【参考方案12】:您的 ID 映射是否正确?如果数据库负责通过标识符创建 Id,则需要将用户对象映射到该 ..
【讨论】:
【参考方案13】:检查您是否忘记为@Id 列添加@GenerateValue。 我对电影和流派之间的多对多关系有同样的问题。程序抛出 休眠错误:org.hibernate.NonUniqueObjectException:具有相同标识符值的不同对象已与会话关联 错误。 后来我发现我只需要确保你有 @GenerateValue 到 GenreId get 方法。
【讨论】:
如何将您的解决方案应用于我的问题?在Task 类中创建一个id 列? ***.com/questions/55732955/…【参考方案14】:我在删除对象时遇到了这个问题,无论是 evict 还是 clear 都没有帮助。
/**
* Deletes the given entity, even if hibernate has an old reference to it.
* If the entity has already disappeared due to a db cascade then noop.
*/
public void delete(final Object entity)
Object merged = null;
try
merged = getSession().merge(entity);
catch (ObjectNotFoundException e)
// disappeared already due to cascade
return;
getSession().delete(merged);
【讨论】:
【参考方案15】:在重复对象开始的位置之前,你应该关闭会话 然后你应该开始一个新的会话
session.close();
session = HibernateUtil.getSessionFactory().openSession();
因此,在一个会话中,具有相同标识符的实体不会超过一个。
【讨论】:
【参考方案16】:我遇到了类似的问题。就我而言,我忘记将数据库中的increment_by
值设置为与cache_size
和allocationSize
使用的值相同。 (箭头指向提到的属性)
SQL:
CREATED 26.07.16
LAST_DDL_TIME 26.07.16
SEQUENCE_OWNER MY
SEQUENCE_NAME MY_ID_SEQ
MIN_VALUE 1
MAX_VALUE 9999999999999999999999999999
INCREMENT_BY 20 <-
CYCLE_FLAG N
ORDER_FLAG N
CACHE_SIZE 20 <-
LAST_NUMBER 180
Java:
@SequenceGenerator(name = "mySG", schema = "my",
sequenceName = "my_id_seq", allocationSize = 20 <-)
【讨论】:
【参考方案17】:聚会迟到了,但可能对即将到来的用户有所帮助 -
当我使用getsession()
选择记录并再次更新另一个具有相同标识符的记录使用same session 导致问题。在下面添加代码。
Customer existingCustomer=getSession().get(Customer.class,1);
Customer customerFromUi;// This customer details comiong from UI with identifer 1
getSession().update(customerFromUi);// Here the issue comes
永远不应该这样做。解决方案是在更新或更改业务逻辑之前驱逐会话。
【讨论】:
【参考方案18】:只需检查 id 是否为 null 或 0 之类的
if(offersubformtwo.getId()!=null && offersubformtwo.getId()!=0)
在将内容从表单设置为 Pojo 的地方添加或更新
【讨论】:
【参考方案19】:我是 NHibernate 的新手,我的问题是我使用不同的会话来查询我的对象而不是保存它。所以保存会话不知道该对象。
这似乎很明显,但通过阅读以前的答案,我到处寻找 2 个对象,而不是 2 个会话。
【讨论】:
【参考方案20】:@GeneratedValue(strategy=GenerationType.IDENTITY),将此注释添加到实体 bean 中的主键属性应该可以解决此问题。
【讨论】:
【参考方案21】:我解决了这个问题。 实际上这是因为我们忘记了 bean 类中 PK 属性的 Generator Type 的实现。所以让它成为任何类型,如
@Id
@GeneratedValue(strategy=GenerationType.IDENTITY)
private int id;
当我们持久化bean的对象时,每个对象都获得相同的ID,所以第一个对象被保存,当另一个对象要持久化时,HIB FW通过这种Exception: org.hibernate.NonUniqueObjectException:
已经关联了具有相同标识符值的不同对象与会话。
【讨论】:
【参考方案22】:问题发生是因为在同一个休眠会话中,您试图保存具有相同标识符的两个对象。有两种解决方案:-
发生这种情况是因为您没有为 id 字段正确配置 mapping.xml 文件,如下所示:-
<id name="id">
<column name="id" sql-type="bigint" not-null="true"/>
<generator class="hibernateGeneratorClass"</generator>
</id>
重载getsession方法以接受像isSessionClear这样的参数, 并在返回当前会话之前清除会话,如下所示
public static Session getSession(boolean isSessionClear)
if (session.isOpen() && isSessionClear)
session.clear();
return session;
else if (session.isOpen())
return session;
else
return sessionFactory.openSession();
这将导致现有会话对象被清除,即使 hibernate 不生成唯一标识符,假设您已使用 Auto_Increment 之类的方法为主键正确配置数据库,它应该适合您。
【讨论】:
【参考方案23】:与 wbdarby 所说的不同,它甚至可以在通过将对象的标识符提供给 HQL 来获取对象时发生。如果尝试修改对象字段并将其保存回数据库(修改可以是插入、删除或更新)在同一会话中,将出现此错误。在保存修改的对象或创建一个全新的会话之前尝试清除休眠会话。 希望我有所帮助;-)
【讨论】:
【参考方案24】:我用杰克逊的新套装替换我的套装时遇到了同样的错误。
为了解决这个问题,我保留了现有的集合,我从旧集合中删除了未知的元素到带有retainAll
的新列表中。
然后我用addAll
添加新的。
this.oldSet.retainAll(newSet);
this.oldSet.addAll(newSet);
无需拥有 Session 并对其进行操作。
【讨论】:
【参考方案25】:试试这个。以下对我有用!
在hbm.xml
文件中
我们需要将class标签的dynamic-update
属性设置为true
:
<class dynamic-update="true">
设置unique列下生成器标签的class属性为identity
:
<generator class="identity">
注意:将唯一列设置为 identity
而不是 assigned
。
【讨论】:
【参考方案26】:我刚刚遇到了同样的问题。我通过添加以下行来解决它:
@GeneratedValue(strategy=GenerationType.IDENTITY)
【讨论】:
【参考方案27】:对我有用的另一件事是使实例变量 Long 代替 long
我有我的主键变量 long id; 将其更改为 Long id;工作过
一切顺利
【讨论】:
【参考方案28】:您始终可以进行会话刷新。 Flush 将同步会话中所有对象的状态(如果我错了,请有人纠正我),也许在某些情况下它会解决你的问题。
实现您自己的等号和哈希码也可能对您有所帮助。
【讨论】:
【参考方案29】:您可以检查您的级联设置。您模型上的级联设置可能会导致此问题。我删除了级联设置(基本上不允许级联插入/更新),这解决了我的问题
【讨论】:
【参考方案30】:我也发现了这个错误。对我有用的是确保主键(即自动生成)不是 PDT(即 long、int 等),而是一个对象(即 Long、Integer 等)
当您创建对象以保存它时,请确保您传递 null 而不是 0。
【讨论】:
以上是关于休眠错误:org.hibernate.NonUniqueObjectException:具有相同标识符值的不同对象已与会话关联的主要内容,如果未能解决你的问题,请参考以下文章