1

我对休眠的奇怪行为有疑问。

我有这样的代码:

Prepod prepod = new Prepod();
        prepod.setId(1l);
        Student student = new Student();
        student.setAge(12l);
        student.setName("name");
        student.setId(1l);
        prepod.getStudents().add(student);
        student.getPrepods().add(prepod);

        Session session = HibernateUtil.getSessionFactory().openSession();
        session.beginTransaction();

        session.saveOrUpdate(prepod);
        session.saveOrUpdate(student);


        session.getTransaction().commit();

冬眠告诉我:

Hibernate: update Student set age=?, name=? where id=?
Exception in thread "main" org.hibernate.StaleStateException: Batch update returned unexpected row count from update [0]; actual row count: 0; expected: 1
    at org.hibernate.jdbc.Expectations$BasicExpectation.checkBatched(Expectations.java:81)
    at org.hibernate.jdbc.Expectations$BasicExpectation.verifyOutcome(Expectations.java:73)
    at org.hibernate.engine.jdbc.batch.internal.NonBatchingBatch.addToBatch(NonBatchingBatch.java:57)
    at org.hibernate.persister.entity.AbstractEntityPersister.update(AbstractEntityPersister.java:3016)
    at org.hibernate.persister.entity.AbstractEntityPersister.updateOrInsert(AbstractEntityPersister.java:2918)
    at org.hibernate.persister.entity.AbstractEntityPersister.update(AbstractEntityPersister.java:3247)
    at org.hibernate.action.internal.EntityUpdateAction.execute(EntityUpdateAction.java:140)
    at org.hibernate.engine.spi.ActionQueue.execute(ActionQueue.java:362)
    at org.hibernate.engine.spi.ActionQueue.executeActions(ActionQueue.java:354)
    at org.hibernate.engine.spi.ActionQueue.executeActions(ActionQueue.java:276)
    at org.hibernate.event.internal.AbstractFlushingEventListener.performExecutions(AbstractFlushingEventListener.java:326)
    at org.hibernate.event.internal.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:52)
    at org.hibernate.internal.SessionImpl.flush(SessionImpl.java:1214)
    at org.hibernate.internal.SessionImpl.managedFlush(SessionImpl.java:403)
    at org.hibernate.engine.transaction.internal.jdbc.JdbcTransaction.beforeTransactionCommit(JdbcTransaction.java:101)
    at org.hibernate.engine.transaction.spi.AbstractTransactionImpl.commit(AbstractTransactionImpl.java:175)
    at logic.Main.main(Main.java:20)
    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:601)
    at com.intellij.rt.execution.application.AppMain.main(AppMain.java:120)

但如果我使用

    session.save(prepod);
    session.save(student);

我懂了:

Hibernate: select max(id) from prepod
Hibernate: select max(id) from Student
Hibernate: insert into prepod (id) values (?)
Hibernate: insert into Student (age, name, id) values (?, ?, ?)
Hibernate: insert into prepod_Student (prepods_id, students_id) values (?, ?)

这对我来说是很好的行为。

你能解释一下为什么会这样吗?

之前我认为 saveOrUpdate 会自动选择保存或更新。

4

1 回答 1

2

问题在于区分对象是否存在于数据库中。

对象的 IDPrepodStudent显然设置为generator="increment" (这就是我们看到这些Select Max(id)语句的原因)。并且很可能unsaved-value保留为默认值:0。

这意味着 Hibernate 将 Prepod 实例视为新的/瞬态的,以防 ID 为 == 0。但在您的代码中,您设置了 id: student.setAge(12l);

因此,对象不再是瞬态的(从休眠的角度来看)。似乎它是现有的,已经持久化的对象。

所以如果SaveOrUpdate被调用,Hibernate 决定使用UPDATE语句,因为对象似乎不是瞬态的。

如何解决?请勿自行设置 ID。只靠generator="increment". 在这种情况下,对象将是瞬态的(默认 id == 0),Hibernate 将按预期工作

于 2013-09-15T07:50:34.053 回答