我正在尝试通过 Hibernate 映射到 MySQL 表来实现一些 Java 对象的持久化。当我提交时,我收到一条消息说“批量更新从更新 [0] 返回了意外的行数;实际行数:0;预期:1'。
我的假设是问题是由于我的 Java POJO 中有一个 long
字段引起的,我想将其用作 MySQL 表中的主键。由于我无法使用 LONG 数据类型作为 MySQL 表中的主键(错误 1170:在没有键长度的键规范中使用了 BLOB/TEXT 列“id”),我从一些谷歌搜索和这个 post 中得出结论。 BIGINT 将是 long
的合适映射。但是它没有更新。
我的测试 POJO Person
非常简单。它有 3 个字段:id (long)、firstname (String)、lastname (String) 以及 setter 和 getter 等。
我在 xml (person.hbm.xml) 中进行 hibernate 映射,本质上看起来像(减去标题):
<hibernate-mapping>
<class name="hibernatetest.Person" table="hibernatetest">
<id name="id" type="long" column="id" >
<generator class="native"/>
</id>
<property name="firstname">
<column name="firstname" />
</property>
<property name="lastname">
<column name="lastname"/>
</property>
</class>
</hibernate-mapping>
我应该保存或更新记录的实际 java 代码片段很简单:
Transaction tr = session.beginTransaction();
Person person = new Person(1,"John","Doe");
session.saveOrUpdate(person);
tr.commit();
就是这样,如果我在 Person 对象和 MySQL 表中将 id
的类型更改为 int (Integer),这一切都可以正常工作。但是,对于我想要保留的实际对象,我没有那个选项,所以问题是;我做错了什么或者我应该怎么做才能让它工作?谢谢。
添加堆栈跟踪:
Hibernate: update hibernatetest set firstname=?, lastname=? where id=?
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:3006)
at org.hibernate.persister.entity.AbstractEntityPersister.updateOrInsert(AbstractEntityPersister.java:2908)
at org.hibernate.persister.entity.AbstractEntityPersister.update(AbstractEntityPersister.java:3237)
at org.hibernate.action.internal.EntityUpdateAction.execute(EntityUpdateAction.java:113)
at org.hibernate.engine.spi.ActionQueue.execute(ActionQueue.java:273)
at org.hibernate.engine.spi.ActionQueue.executeActions(ActionQueue.java:265)
at org.hibernate.engine.spi.ActionQueue.executeActions(ActionQueue.java:187)
at org.hibernate.event.internal.AbstractFlushingEventListener.performExecutions(AbstractFlushingEventListener.java:337)
at org.hibernate.event.internal.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:50)
at org.hibernate.internal.SessionImpl.flush(SessionImpl.java:1082)
at org.hibernate.internal.SessionImpl.managedFlush(SessionImpl.java:317)
at org.hibernate.engine.transaction.internal.jdbc.JdbcTransaction.beforeTransactionCommit(JdbcTransaction.java:101)
at org.hibernate.engine.transaction.spi.AbstractTransactionImpl.commit(AbstractTransactionImpl.java:175)
at com.hibernate.test.TestMain.main(TestMain.java:38)
nested transactions not supported
更新: 好的,我终于解决了。我将 hibernate 生成器类从“ native ”更改为“已分配”,现在它按预期工作。所以现在 hibernate 映射看起来像:
<hibernate-mapping>
<class name="hibernatetest.Person" table="hibernatetest">
<id name="id" type="long" column="id" >
<generator class="assigned"/>
</id>
<property name="firstname">
<column name="firstname" />
</property>
<property name="lastname">
<column name="lastname"/>
</property>
</class>
</hibernate-mapping>
必须承认,我不知道该参数的含义(从某处复制),也不知道它会引起这么多麻烦。找到这个explanation这非常有用。
显然我没有足够的凭据来回答我自己的问题,所以我想它会保持开放状态,或者如果有人提供空答案,我会接受。谢谢。
最佳答案
当您使用 saveOrUpdate()
如果对象的 ID 是 null
,方法 hibernate 会触发插入查询和 update
如果它是任何其他值。 我可以看到代码,
Person person = new Person(1,"John","Doe");
设置 id
至 1
并调用 saveOrUpdate()
方法。我假设没有 id 1 的条目,因此会抛出错误。
要使其正常工作,您需要进行以下更改。
更改
id
的类型亲自到Long
来自long
(包装类,以便它可以支持 null)。编写构造函数
new Person("John","Doe");
并保存该对象。
保留 <generator class="assigned"/>
不是一个好主意对于交易数据。相反,您应该坚持 native
正如您首先尝试的那样。
我觉得这是解决您最初问题的一种更简洁的方法,即使您已经找到了替代解决方案。
关于java - LONG 作为 Hibernate 映射到 MySQL 的主键,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8339807/