简体   繁体   中英

NonUniqueObjectException when trying to batch insert Objects with Auto-Generated ID

I am trying to bulk insert a List of objects. I have the ID configured to be auto generated. Previously I had the following:

<id name="entryId" type="integer"  column="ENTRY_ID">
    <generator class="seqhilo"> 
        <param name="sequence">HB_ENTRY_ID_SEQ</param>
        <param name="max_lo">50</param>
    </generator>
</id>

And my insert query was as follows:

try (Session session = sessionFactory.openSession()) {
    session.beginTransaction();

    for (int i = 0; i < insertList.size(); i++) {
        session.save(insertList.get(i));
        if (i % 100 == 0) {
            session.flush();
            session.clear();
        }
    }

    session.getTransaction().commit();
    return insertList.size();
}

I have the correct batch_size property value set as well. The above worked fine, however, recently I changed my code to be annotation based and I have the following:

@Id
@Column(name = "ENTRY_ID")
@GeneratedValue(generator = "hibSeq", strategy = GenerationType.SEQUENCE)
@SequenceGenerator(name = "hibSeq", sequenceName = "HB_ENTRY_ID_SEQ", allocationSize = 100)

When I run this now, the insert throws a org.hibernate.NonUniqueObjectException: A different object with the same identifier value was already associated with the session

I've been trying to understand this error as per here and here but haven't been able to resolve my issue. As far as I can tell, something is happening at the session.flush()/clear() stage that causes the sequence generator to recycle an ID that has already been used.

What am I doing wrong?

The generator provided in the XML is not the same one as that specified by the annotation. The former is a sequence hilo, which will generate an ID prefix based on the value returned from a sequence.

The latter takes the value of the sequence: it keeps that value and the next 100 in memory (as per allocationSize ), this allows you to avoid making 100 calls. However, after 100 IDs have been generated, it will call nextval and generate the same ID as the one that the second entry:

Generated ID 0 (query) .NEXTVAL
Generated ID 1 (in memory)
Generated ID 2 (in memory)
...
Generated ID 100 (in memory)
Generated ID 1 (query) .NEXTVAL

Solution here is to ALTER SEQUENCE HB_ENTRY_ID_SEQ INCREMENT BY 100

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM