[已解决] Hibernate中NonUniqueObjectException: A different object with the same identifier 错误

在Hibernate写一个循环插入数据的test:

import Entity.User;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;

public class Test {
    public static void main(String[] args) {
        SessionFactory sf = new Configuration().configure().buildSessionFactory();
        Session s = sf.openSession();
        s.beginTransaction();

        for(int i=1;i<=10;i++){
            User a = new User();
            a.setName("client"+i);
            a.setBalance(i+123.41+i*123.51);
            s.save(a);
        }

        s.getTransaction().commit();
        s.close();
        sf.close();
    }
}

但是运行时报错:
Exception in thread "main" org.hibernate.NonUniqueObjectException: A different object with the same identifier value was already associated with the session : [Entity.User#0]

似乎是提示插入的这些数据中的identifier是重复的, 但是我在数据库中的id字段是设置了auto-increment的, 按理说不会出现id重复的情况;

了解了hibernate的事务运行方式:
应用使用session.save()保存对象,这个时候Session将这个对象放入entityEntries,用来标记对象已经和当前的会话建立了关联,由于应用对对对象做了保存的操作,Session还要在insertions中登记应用的这个插入行为(行为包括:对象引用、对象id、Session、持久化处理类)。即,其实调用session.save(class)之后,hibernate并不会立即提交数据库,而是先将要保存,更新,删除放进了缓存中(为什么要这样做呢?我想应该是,一方面数据永久化,实际上是将数据保存到硬盘等存储介质,学过操作系统的人都知道,外存的读取和存放的消耗是主存的几个数量级别的消耗,先放到缓存中,然后一次性写入到存储介质,减少了读写消耗;另一方面,应该是为了高效率实现事务滚回,众所皆知,事务具有原子性,要么都成功完成,要么都失败,那么如果一个事务要调用多个dao层实现数据的增删改查,如果hibernate是一条修改语句就立刻修改数据库的数据,一条删除语句就删除了,那如果删除语句删除失败,那又要去硬盘修改回去数据,那么这样会大大增大cpu的资源消耗,但如果这些一开始是放到缓存中进行标记,最后如果事务完成,则自动将缓存标记的操作写入到数据库,这样就能提高资源利用率了,这就是hibernate自带的一级缓存功能),等整个事务操作完成后,事务提示,需要将所有缓存flush入数据库,Session启动一个事务,并按照insert ,update,…,delete的顺序提交所有之前登记的操作(注意:所有insert执行完毕后才会执行update,这里的特殊处理也可能会将你的程序搞得一团遭,如需要控制操作的顺序,需要使用flush)

所以这里需要在hibernate的配置文件中声明id这个字段是使用generator自动生成的:
这样就对了:

<id name="id">
    <column name="id" sql-type="int(11)"/>
    <generator class="native"/>
</id>

完整的配置文件:

<?xml version='1.0' encoding='utf-8'?>
<!DOCTYPE hibernate-mapping PUBLIC
    "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
    "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping>

    <class name="Entity.User" table="user" schema="demo">
        <id name="id">
            <column name="id" sql-type="int(11)"/>
            <generator class="native"/>
        </id>
        <property name="name">
            <column name="name" sql-type="varchar(255)" not-null="true"/>
        </property>
        <property name="balance">
            <column name="balance" sql-type="float" precision="-1" not-null="true"/>
        </property>
    </class>
</hibernate-mapping>

猜你喜欢

转载自blog.csdn.net/qq_33982232/article/details/86762099