hibernate中一种导致a different object with the same identifier value was already associated with the session错误方式及解决方法

先将自己出现错误的全部代码都贴出来:

hibernate.cfg.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-configuration PUBLIC
        "-//Hibernate/Hibernate Configuration DTD 3.0//EN"
        "http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
    <session-factory>
        <property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
        <property name="hibernate.connection.password">tiger</property>
        <property name="hibernate.connection.url">jdbc:mysql:///hibernate?useUnicode=true&amp;characterEncoding=UTF-8</property>
        <property name="hibernate.connection.username">root</property>
        <property name="hibernate.dialect">org.hibernate.dialect.MySQLDialect</property>

        <property name="show_sql">true</property>
        <property name="format_sql">true</property>
        <property name="hbm2ddl.auto">create</property>

        <mapping resource="com/third/Dao1/Grader1.hbm.xml"/>
        <mapping resource="com/third/Dao1/Students1.hbm.xml"/>
    </session-factory>
</hibernate-configuration>

Students1.java

package com.third.Dao1;

import java.io.Serializable;

public class Students1 implements Serializable {

    private int sid;
    private String sname;
    private String sgender;

    public Students1() {

    }

    public int getSid() {
        return sid;
    }

    public void setSid(int sid) {
        this.sid = sid;
    }

    public String getSname() {
        return sname;
    }

    public void setSname(String sname) {
        this.sname = sname;
    }

    public String getSgender() {
        return sgender;
    }

    public void setSgender(String sgender) {
        this.sgender = sgender;
    }

}

Grader1.java

package com.third.Dao1;

import java.io.Serializable;
import java.util.HashSet;
import java.util.Set;

public class Grader1 implements Serializable {

    private int gid;
    private String gname;
    private Set<Students1> stuSet=new HashSet<Students1>();

    public Grader1() {

    }

    public int getGid() {
        return gid;
    }
    public void setGid(int gid) {
        this.gid = gid;
    }
    public String getGname() {
        return gname;
    }
    public void setGname(String gname) {
        this.gname = gname;
    }

    public Set<Students1> getStuSet() {
        return stuSet;
    }

    public void setStuSet(Set<Students1> stuSet) {
        this.stuSet = stuSet;
    }

}

由eclipse帮助生成的hbm.xml文件:

Students1.hbm.xml

<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<!-- Generated 2017-3-1 20:42:49 by Hibernate Tools 3.5.0.Final -->
<hibernate-mapping>
    <class name="com.third.Dao1.Students1" table="STUDENTS1">
        <id name="sid" type="int">
            <column name="SID" />
            <generator class="assigned" />
        </id>
        <property name="sname" type="java.lang.String">
            <column name="SNAME" />
        </property>
        <property name="sgender" type="java.lang.String">
            <column name="SGENDER" />
        </property>
    </class>
</hibernate-mapping>

Grader1.cfg.xml

<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<!-- Generated 2017-3-1 20:42:49 by Hibernate Tools 3.5.0.Final -->
<hibernate-mapping>
    <class name="com.third.Dao1.Grader1" table="GRADER1">
        <id name="gid" type="int">
            <column name="GID" />
            <generator class="increment" />
        </id>
        <property name="gname" type="java.lang.String">
            <column name="GNAME" />
        </property>
        <set name="stuSet" inverse="false" table="STUDENTS1" lazy="true">
            <key>
                <column name="GID" />
            </key>
            <one-to-many class="com.third.Dao1.Students1" />
        </set>
    </class>
</hibernate-mapping>

测试文件:

Test.java

 1 package com.third;
 2
 3 import java.util.HashSet;
 4 import java.util.Set;
 5
 6 import org.hibernate.Session;
 7 import org.hibernate.SessionFactory;
 8 import org.hibernate.Transaction;
 9 import org.hibernate.cfg.Configuration;
10 import org.hibernate.service.ServiceRegistry;
11 import org.hibernate.service.ServiceRegistryBuilder;
12 import org.junit.After;
13 import org.junit.Before;
14 import org.junit.Test;
15
16 import com.third.Dao1.Grader1;
17 import com.third.Dao1.Students1;
18
19 /*import com.third.Dao.Grader;
20 import com.third.Dao.Students;*/
21 public class Test1 {
22
23     private static SessionFactory sessionFactory;
24     private static Session session;
25     private static Transaction transaction;
26     @Before
27     public void init(){
28         //创建配置对象,匹配读取hibernate.cfg.xml文件
29         Configuration config=new Configuration().configure();
30         //获取服务注册对象(该对象中封装了hibernate.cfg.xml文件中的<properties>、<mapping>信息)
31         ServiceRegistry serviceRegistry=new ServiceRegistryBuilder()
32                  .applySettings(config.getProperties()).buildServiceRegistry();
33         //获取sessionFactory对象(该对象中通过传参serviceRegistry对象,获取了<mapping><properties>信息)
34          sessionFactory=config.buildSessionFactory(serviceRegistry);
35     }
55
56     @Test
57     public void test2(){
58         //通过sessionFactory对象获取session对象
59         session=sessionFactory.openSession();
60         //通过session对象开启事务,并返回Transaction对象
61         transaction=session.beginTransaction();
62
63         //创建students和Grader对象
64         Students1 student2=new Students1();
65         student2.setSname("小美");
66         student2.setSgender("女");
67         Students1 student3=new Students1();
68         student3.setSname("小宏");
69         student3.setSgender("女");
70
71         Set<Students1> stuSet=new HashSet<Students1>();
72         stuSet.add(student2);
73         stuSet.add(student3);
74
75         //实例Grader对象
76         Grader1 grader2=new Grader1();
77         grader2.setGname("信息与计算科学二班");
78         grader2.setStuSet(stuSet);;
79
80
81         session.save(student2);
82
83         session.save(student3);
84         session.save(grader2);
85     }
86     @After
87     public void destory(){
88         //提交事务
89         transaction.commit();
90         //关闭资源
91         if(session!=null){
92             session.close();
93         }
94         if(sessionFactory!=null){
95             sessionFactory.close();
96         }
97     }
98 }

下面是报错的报文:

org.hibernate.NonUniqueObjectException: a different object with the same identifier value was already associated with the session: [com.third.Dao1.Students1#0]
    at org.hibernate.event.internal.AbstractSaveEventListener.performSave(AbstractSaveEventListener.java:179)
    at org.hibernate.event.internal.AbstractSaveEventListener.saveWithGeneratedId(AbstractSaveEventListener.java:135)
    at org.hibernate.event.internal.DefaultSaveOrUpdateEventListener.saveWithGeneratedOrRequestedId(DefaultSaveOrUpdateEventListener.java:206)
    at org.hibernate.event.internal.DefaultSaveEventListener.saveWithGeneratedOrRequestedId(DefaultSaveEventListener.java:55)
    at org.hibernate.event.internal.DefaultSaveOrUpdateEventListener.entityIsTransient(DefaultSaveOrUpdateEventListener.java:191)
    at org.hibernate.event.internal.DefaultSaveEventListener.performSaveOrUpdate(DefaultSaveEventListener.java:49)
    at org.hibernate.event.internal.DefaultSaveOrUpdateEventListener.onSaveOrUpdate(DefaultSaveOrUpdateEventListener.java:90)
    at org.hibernate.internal.SessionImpl.fireSave(SessionImpl.java:764)
    at org.hibernate.internal.SessionImpl.save(SessionImpl.java:756)
    at org.hibernate.internal.SessionImpl.save(SessionImpl.java:752)
    at com.third.Test1.test2(Test1.java:83)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:606)
    at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:45)
    at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:15)
    at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:42)
    at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:20)
    at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:28)
    at org.junit.internal.runners.statements.RunAfters.evaluate(RunAfters.java:30)
    at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:263)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:68)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:47)
    at org.junit.runners.ParentRunner$3.run(ParentRunner.java:231)
    at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:60)
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:229)
    at org.junit.runners.ParentRunner.access$000(ParentRunner.java:50)
    at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:222)
    at org.junit.runners.ParentRunner.run(ParentRunner.java:300)
    at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:86)
    at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:459)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:675)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:382)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:192)

原因分析:

第一步:

报错报文中我们重点看加红的两行信息,第一行:

a different object with the same identifier value was already associated with the session: [com.third.Dao1.Students1#0]

大致的意思说:一个不同的Object对象和session:[com.third.Dao1.Students1#0]中已有的一个对象拥有着相同的唯一辨识符。我们仔细看这段代码,这段代码的主要作用是向Mysql数据库中创建两个关联表格,并且向表中添加一些信息。我们在分析一下这个报错是在我们编写的哪行代码执行不下去了之后,然后抛出异常。

第二步:

很明显:at com.third.Test1.test2(Test1.java:83)

这行错误报文指出我们是在Test1.java代码的83行抛出的异常,我们找到这行代码:session.save(student3);分析这行代码具体执行情况,在这之前只有session.save(students2);代码对session:[com.third.Dao1.Students1#0]操作,这样我们就将这两行代码结合在一起分析。之前说报错的原因是:session:[com.third.Dao1.Students1#0]中已有的对象的唯一标识符和新添加的对象相同,从而产生冲突。而session:[com.third.Dao1.Students1#0]中之前只有代码session.save(students2);对它进行了操作,也就是session:[com.third.Dao1.Students1#0]中只添加了studnets2这一个对象,这样要新添加的对象students3就和students2对象在唯一标识符上冲突。

第三步:

我们打开Navicat for MySQL软件,查看已经由eclipse创建的表格students1的表格结构(通过点击students1表格右键,选择设计表)

很明显表格students1记录的主键是SID,即在session:[com.third.Dao1.Students1#0]中的唯一表示符就是sid,那么我们看看表格中已有的students2的对象记录的主键:

我们能够看到students1表格中有一条SID为0的SNAME为小美的记录,我们可以知道session:[com.third.Dao1.Students1#0]中students2对象的唯一标识符sid为0,而students3对象唯一标识符和它相同冲突,这样students3对象的唯一表示符也将是sid为0。

第四步:

然后我们需要思考,为什么两个对象的唯一标识符都为0,这样我们就需要回到Test1.java代码中去分析,看看对于这个唯一标识符是如何设置的,即查看students2.setSid()和students3.setSid()函数的调用赋值情况。我们在查看完@Test代码段的代码发现,整段代码没有调用students2.setSid()和students3.setSid()函数,当时在设计这个程序时,想法是将主键SID交由MySQL数据库自行递增。所以自己写的代码段就没有对sid进行set赋值。但是MySQL数据库并没有完成主键SID的自动赋值(之前说students2和students3对象的唯一标识符sid都为0,在数据库表格中表现为主键SID都为0),这里就需要讨论数据库的主键的生成策略,而主键的生成策略是由.hbm.xml文件中指定的,这样我们就需要分析Students1.hbm.xml代码,其中控制主键生成策略的是<generator class="" />标签,我们很快找到了这个标签,查看这个标签主键生成策略的设置情况:

我们能看到这里设置的主键生成策略是assigned,而assigned适用于自然主键,由Java应用程序负责生成标识符,也就是说需要我们手动使用setSid()函数手动赋值。而我们并没有进行手动set赋值,而MySQL数据库在assirned主键生成策略下,如果不进行手动set赋值,其主键SID的值将会采取默认的值0,这就解释了唯一标识符sid都是0的冲突问题。

解决方法:(给出两种)

1、修改Students1.hbm.xml代码,其他代码不需要改变:

<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<!-- Generated 2017-3-1 20:42:49 by Hibernate Tools 3.5.0.Final -->
<hibernate-mapping>
    <class name="com.third.Dao1.Students1" table="STUDENTS1">
        <id name="sid" type="int">
            <column name="SID" />
            <generator class="increment" />
        </id>
        <property name="sname" type="java.lang.String">
            <column name="SNAME" />
        </property>
        <property name="sgender" type="java.lang.String">
            <column name="SGENDER" />
        </property>
    </class>
</hibernate-mapping>

修改的代码是绿色背景的代码,将主键生成策略改成increment(适用于代理主键,由hibernate自动递增方式生成)或者改成native(适用于代理主键,根据底层数据库对自动生成标识符的方式自动选择,其中MySQL是自动递增方式生成)。

2、修改Test1.java代码,其他代码不需要改动。

 1 package com.third;
 2
 3 import java.util.HashSet;
 4 import java.util.Set;
 5
 6 import org.hibernate.Session;
 7 import org.hibernate.SessionFactory;
 8 import org.hibernate.Transaction;
 9 import org.hibernate.cfg.Configuration;
10 import org.hibernate.service.ServiceRegistry;
11 import org.hibernate.service.ServiceRegistryBuilder;
12 import org.junit.After;
13 import org.junit.Before;
14 import org.junit.Test;
15
16 import com.third.Dao1.Grader1;
17 import com.third.Dao1.Students1;
18
19 /*import com.third.Dao.Grader;
20 import com.third.Dao.Students;*/
21 public class Test1 {
22
23     private static SessionFactory sessionFactory;
24     private static Session session;
25     private static Transaction transaction;
26     @Before
27     public void init(){
28         //创建配置对象,匹配读取hibernate.cfg.xml文件
29         Configuration config=new Configuration().configure();
30         //获取服务注册对象(该对象中封装了hibernate.cfg.xml文件中的<properties>、<mapping>信息)
31         ServiceRegistry serviceRegistry=new ServiceRegistryBuilder()
32                  .applySettings(config.getProperties()).buildServiceRegistry();
33         //获取sessionFactory对象(该对象中通过传参serviceRegistry对象,获取了<mapping><properties>信息)
34          sessionFactory=config.buildSessionFactory(serviceRegistry);
35     }
36
37
38     @Test
39     public void test2(){
40         //通过sessionFactory对象获取session对象
41         session=sessionFactory.openSession();
42         //通过session对象开启事务,并返回Transaction对象
43         transaction=session.beginTransaction();
44
45         //创建students和Grader对象
46         Students1 student2=new Students1();
47         student2.setSname("小美");
48         student2.setSgender("女");
49         student2.setSid(1);
50         Students1 student3=new Students1();
51         student3.setSname("小宏");
52         student3.setSgender("女");
53         student3.setSid(2);
54
55         Set<Students1> stuSet=new HashSet<Students1>();
56         stuSet.add(student2);
57         stuSet.add(student3);
58
59         //实例Grader对象
60         Grader1 grader2=new Grader1();
61         grader2.setGname("信息与计算科学二班");
62         grader2.setStuSet(stuSet);;
63
64
65         session.save(student2);
66
67         session.save(student3);
68         session.save(grader2);
69     }
70     @After
71     public void destory(){
72         //提交事务
73         transaction.commit();
74         //关闭资源
75         if(session!=null){
76             session.close();
77         }
78         if(sessionFactory!=null){
79             sessionFactory.close();
80         }
81     }
82 }

添加绿色背景的两段代码,手动的添加唯一标识符的值。

总结:

出现a different object with the same identifier value was already associated with the session的错误的原因是session中的对象的唯一标识符相同的冲突,其根本就是表现在数据库中的表格中的主键值相同的冲突或者其他唯一标识符冲突。解决这个冲突,我们必须知道,到底是哪个唯一标识符冲突,然后再去修改掉相同的标识符,让他们值不再相同,这样问题就解决了~

时间: 2025-01-31 03:46:58

hibernate中一种导致a different object with the same identifier value was already associated with the session错误方式及解决方法的相关文章

[转]解决a different object with the same identifier value was already associated with the session错误

NonUniqueObjectException 解决a different object with the same identifier value was already associated with the session错误 org.hibernate.NonUniqueObjectException: a different object with the same identifier value was already associated with the session:

解决a different object with the same identifier value was already associated with the session错误

20:41:15 今天做一个saveorupdate操作报错: org.springframework.orm.hibernate3.HibernateSystemException: a different object with the same identifier value was already associated with the session: [com.xshcar.carcloud.entity.UboxTbl#1291]; nested exception is org

IOS开发中 常常遇到的遇到的警告,错误汇总,解决方法

从sdk3.2.5升级到sdk 5.1中间废弃了很多的方法,还有一些逻辑关系更加严谨了. 1,警告:"xoxoxoxo"  is deprecated 解决办法:查看xoxoxoxo的这个方法的文档,替换掉这个方法即可. 2,警告:Declaration of "struct sockaddr" will not be visible outside of this function 解决办法:在你的开源.m文件中添加 #import <netinet/in.

利用struts进行前端页面间传值及hibernate异常:a different object with the same identifier value was already associated with the session的总结

2017-3-16 我使用SSH框架在做单表CRUD的更新操作时遇到了一个问题,就是页面间该怎么传值?解决该需求时引发了一系列的bug,趁还记得好好总结一番. 前端页面间传值 情景:在我查出所以记录后,点击修改会链接到新的修改页面. 问题:该新页面没有之前的实体信息,该如何传递要修改的实体信息给该页面,例如id? 思路1:利用struts的action来传值. 1 <form action="deleteSerCate.action" method="post"

Hibernate更新数据报错:a different object with the same identifier value was already associated with the session: [com.elec.domain.ElecCommonMsg#297e35035c28c368015c28c3e6780001]

使用hibernate更新数据时,报错 Struts has detected an unhandled exception: Messages: a different object with the same identifier value was already associated with the session: [com.elec.domain.ElecCommonMsg#297e35035c28c368015c28c3e6780001] a different object w

org.hibernate.NonUniqueObjectException: a different object with the same identifier value was already associated with the session异常解决办法

org.hibernate.NonUniqueObjectException: a different object with the same identifier value was already associated with the session异常解决办法 为什么还会说已经存在相同的session了呢.然后每次将项目重启后第一次编辑的时候问题不会触发,只有当第二次操作的时候才会出现这个问题. 解决办法:关闭session.好好检查操作完成后有没有关闭会话. org.hibernat

a different object with the same identifier value was already associated with the session

错误提示: org.springframework.dao.DuplicateKeyException: a different object with the same identifier value was already associated with the session: [cn.itcast.bos.domain.User#4]; nested exception is org.hibernate.NonUniqueObjectException: a different obj

关于CUDA C 项目中“ error C2059: 语法错误:“&lt;” ”问题的解决方法

该问题的关键在于理解CUDA项目中C\C++文件需要由c++编译器进行编译,而CUDA C的源文件需要由CUDA的编译器nvcc.exe进行编译. 发生该语法错误的原因是cu文件被C++编译器所编译,C++编译器无法识别 "<<<",导致报错. 为什么cu文件会被C++编译器所编译呢?原因在于我们使用#include将cu文件包含到了C++文件中.对于#include的用途,更简单的理解就是把几个文件合并成一个文件,所以,当编译C++文件中,包含其中的cu文件也会被编

LAMP系列之PHP编译过程中常见错误信息的解决方法

LAMP系列之PHP编译过程中常见错误信息的解决方法 在CentOS编译PHP5的时候有时会遇到以下的一些错误信息,基本上都可以通过yum安装相应的库来解决.以下是具体的一些解决办法: ******************************************************************************* checking for BZip2 support- yes checking  for BZip2 in default path- not foun