休眠错误: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 从员工表中读取记录 现在您已经在 J​​ava 中修改了记录。 您将把员工记录保存在数据库中。 我们在这里的任何地方都没有结束会议。 由于被读取的对象也保留在会话中。它与我们希望写入的对象冲突。因此出现了这个错误。

【讨论】:

【参考方案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_sizeallocationSize 使用的值相同。 (箭头指向提到的属性)

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:具有相同标识符值的不同对象已与会话关联的主要内容,如果未能解决你的问题,请参考以下文章

选择值时出现休眠错误

休眠错误,如何解决?

休眠命名查询不知道错误

[休眠]错误:找不到实体类:

休眠 JPA 错误

我在@OneToMany 休眠映射中遇到错误?