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&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
package com.third; import java.util.HashSet;
import java.util.Set; import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.cfg.Configuration;
import org.hibernate.service.ServiceRegistry;
import org.hibernate.service.ServiceRegistryBuilder;
import org.junit.After;
import org.junit.Before;
import org.junit.Test; import com.third.Dao1.Grader1;
import com.third.Dao1.Students1; /*import com.third.Dao.Grader;
import com.third.Dao.Students;*/
public class Test1 { private static SessionFactory sessionFactory;
private static Session session;
private static Transaction transaction;
@Before
public void init(){
//创建配置对象,匹配读取hibernate.cfg.xml文件
Configuration config=new Configuration().configure();
//获取服务注册对象(该对象中封装了hibernate.cfg.xml文件中的<properties>、<mapping>信息)
ServiceRegistry serviceRegistry=new ServiceRegistryBuilder()
.applySettings(config.getProperties()).buildServiceRegistry();
//获取sessionFactory对象(该对象中通过传参serviceRegistry对象,获取了<mapping><properties>信息)
sessionFactory=config.buildSessionFactory(serviceRegistry);
} @Test
public void test2(){
//通过sessionFactory对象获取session对象
session=sessionFactory.openSession();
//通过session对象开启事务,并返回Transaction对象
transaction=session.beginTransaction(); //创建students和Grader对象
Students1 student2=new Students1();
student2.setSname("小美");
student2.setSgender("女");
Students1 student3=new Students1();
student3.setSname("小宏");
student3.setSgender("女"); Set<Students1> stuSet=new HashSet<Students1>();
stuSet.add(student2);
stuSet.add(student3); //实例Grader对象
Grader1 grader2=new Grader1();
grader2.setGname("信息与计算科学二班");
grader2.setStuSet(stuSet);; session.save(student2); session.save(student3);
session.save(grader2);
}
@After
public void destory(){
//提交事务
transaction.commit();
//关闭资源
if(session!=null){
session.close();
}
if(sessionFactory!=null){
sessionFactory.close();
}
}
}
下面是报错的报文:
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代码,其他代码不需要改动。
package com.third; import java.util.HashSet;
import java.util.Set; import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.cfg.Configuration;
import org.hibernate.service.ServiceRegistry;
import org.hibernate.service.ServiceRegistryBuilder;
import org.junit.After;
import org.junit.Before;
import org.junit.Test; import com.third.Dao1.Grader1;
import com.third.Dao1.Students1; /*import com.third.Dao.Grader;
import com.third.Dao.Students;*/
public class Test1 { private static SessionFactory sessionFactory;
private static Session session;
private static Transaction transaction;
@Before
public void init(){
//创建配置对象,匹配读取hibernate.cfg.xml文件
Configuration config=new Configuration().configure();
//获取服务注册对象(该对象中封装了hibernate.cfg.xml文件中的<properties>、<mapping>信息)
ServiceRegistry serviceRegistry=new ServiceRegistryBuilder()
.applySettings(config.getProperties()).buildServiceRegistry();
//获取sessionFactory对象(该对象中通过传参serviceRegistry对象,获取了<mapping><properties>信息)
sessionFactory=config.buildSessionFactory(serviceRegistry);
} @Test
public void test2(){
//通过sessionFactory对象获取session对象
session=sessionFactory.openSession();
//通过session对象开启事务,并返回Transaction对象
transaction=session.beginTransaction(); //创建students和Grader对象
Students1 student2=new Students1();
student2.setSname("小美");
student2.setSgender("女");
student2.setSid(1);
Students1 student3=new Students1();
student3.setSname("小宏");
student3.setSgender("女");
student3.setSid(2); Set<Students1> stuSet=new HashSet<Students1>();
stuSet.add(student2);
stuSet.add(student3); //实例Grader对象
Grader1 grader2=new Grader1();
grader2.setGname("信息与计算科学二班");
grader2.setStuSet(stuSet);; session.save(student2); session.save(student3);
session.save(grader2);
}
@After
public void destory(){
//提交事务
transaction.commit();
//关闭资源
if(session!=null){
session.close();
}
if(sessionFactory!=null){
sessionFactory.close();
}
}
}
添加绿色背景的两段代码,手动的添加唯一标识符的值。
总结:
出现a different object with the same identifier value was already associated with the session的错误的原因是session中的对象的唯一标识符相同的冲突,其根本就是表现在数据库中的表格中的主键值相同的冲突或者其他唯一标识符冲突。解决这个冲突,我们必须知道,到底是哪个唯一标识符冲突,然后再去修改掉相同的标识符,让他们值不再相同,这样问题就解决了~
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错误
[转]解决a different object with the same identifier value was already associated with the session错误 这个错 ...
- vue中npm run dev运行项目不能自动打开浏览器! 以及 webstorm跑vue项目jshint一直提示错误问题的解决方法!
vue中npm run dev运行项目不能自动打开浏览器!以及 webstorm跑vue项目jshint一直提示错误问题的解决方法! 1.上个项目结束就很久没有使用vue了,最近打算用vue搭建自己的 ...
- [转]解决a different object with the same identifier value was already associated with the session错误
1.a different object with the same identifier value was already associated with the session. 错误原因:在h ...
- 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 thesession时,一般是因为在h ...
- hibernate的报错信息a different object with the same identifier value was already associated with the session解决办法
废话不多说,直接说原因,这是在hibernate中,有2个相同类型的实体类具有同样的主键标识符,然后调用update或者调用saveOrUpdate,我朋友出这个错的由于他想要update一条数据时, ...
- Hibernate中3种结果转换的详细说明(转)
Hibernate中3种结果转换的详细说明 在hibernate使用的过程中.我们通常需要对结果进行解释. Hibernate为我们提供了以下3种解释方法: Transformers.ALIAS_TO ...
- Hibernate Error: a different object with the same identifier value was already associated with the session
在执行Hibernate的Update操作时,报错:a different object with the same identifier value was already associated w ...
- Exception 06 : 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 ...
- 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 th ...
随机推荐
- Twisted源码分析系列01-reactor
转载自:http://www.jianshu.com/p/26ae331b09b0 简介 Twisted是用Python实现的事件驱动的网络框架. 如果想看教程的话,我觉得写得最好的就是Twisted ...
- Win10 的虛擬桌面
Win10 的虛擬桌面我覺得蠻多餘的,平常很少用,除非是像以前的 "切換老闆鍵" ,老闆來了,你不想讓他知道你在幹嘛,趕快切換另外一個桌面. 切換工作視窗:Alt + Tab 叫出 ...
- Swift 添加到TableView实现动画效果
let indexPath = NSIndexPath(forRow:0 ,inSection:0) self.tableView.insertRowsAtIndexPaths([indexPath] ...
- js原生设计模式——10适配器模式之参数适配器
原理:参数适配器说白了就是给出要带入数据字段的对应字段的默认值,一旦数据字段值不足,就取默认值补足. [写法一]:直接返回 <!DOCTYPE html><html lang=&qu ...
- js原生之设计模式开篇介绍
本文主要讲述一下,什么是设计模式(Design pattern),作为敲键盘的我们要如何学习设计模式.设计模式真的是一把万能钥匙么? 各个代码的设计模式几乎每个人都知晓,就算不会那也一定在一些 ...
- Carthage - 一个简单、去集中化的Cocoa依赖管理器
作为一名新时代的90后猿 在swift大势所趋的时候 怎能不会Carthage 配置它其实很简单 下面我们一步一步来 (1)打开你的终端 输入 brew update brew install c ...
- JavaSwing JScrollPane的使用
JavaSwing JScrollPane的使用: 参考:http://duyz.blog.ifeng.com/article/340649.html package com.srie.test; i ...
- git 终端克隆
mac版 用终端克隆码云中的文档到PC端 第一步:cd desktop //打开桌面 第二步:ls //打印桌面 第三步:(cd +建好的文件夹拖进去) //自己建好的文件夹 或者cd + 文件名 ...
- .Net多线程编程—使用Visual Studio 2012进行调试
1 相关概念 1)栈帧 C语言中,每个栈帧对应着一个未运行完的函数.栈帧中保存了该函数的返回地址和局部变量. 栈帧也叫过程活动记录,是编译器用来实现过程/函数调用的一种数据结构. 2)单步执行与单步函 ...
- Java内存回收优化及配置
原文链接:http://eol.cqu.edu.cn/eol/jpk/course/preview/jpkmaterials_folder_txtrtfview.jsp?resId=23156& ...