【问题标题】:LONG as primary key in Hibernate mapping to MySQLLONG 作为 Hibernate 映射到 MySQL 的主键
【发布时间】:2011-12-01 10:27:04
【问题描述】:

我正在尝试通过 Hibernate 映射到 MySQL 表来实现一些 Java 对象的持久性。当我提交时,我收到一条消息说'批量更新从更新 [0] 中返回了意外的行数;实际行数:0;预计:1'。

我的假设是,问题是由于我的 Java POJO 中有一个 long-字段,我想将其用作 MySQL 表中的主键。由于我无法在 MySQL 表中使用数据类型 LONG 作为我的主键(错误 1170:BLOB/TEXT 列 'id' 在没有键长度的键规范中使用)我从一些谷歌搜索得出结论,这个post BIGINT 将是long 的合适映射。但是它没有更新。

我的测试POJOPerson很简单。它有 3 个字段:id (long)、firstname (String)、lastname (String) 以及 setter 和 getter 等。

我在 xml (person.hbm.xml) 中进行休眠映射,基本上看起来像(减去标题):

<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 代码 sn-p 很简单:

Transaction tr = session.beginTransaction();            
Person person = new Person(1,"John","Doe");
session.saveOrUpdate(person);
tr.commit();

事情就是这样,如果我在 Person 对象和 MySQL 表中将 id 的类型更改为 int(整数),这一切都可以正常工作。但是,对于要保留的实际对象,我没有该选项,所以问题是;我做错了什么或者我应该怎么做才能让它工作?谢谢。

添加堆栈跟踪:

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-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 很有用。

显然我没有足够的凭据来回答我自己的问题,所以我猜它会保持开放,或者如果有人提供空答案,我会接受它。谢谢。

【问题讨论】:

  • 你能发布你的完整堆栈跟踪吗,long 和 BIGINT 应该可以正常工作,我个人使用它没有发现问题,请分享你的堆栈跟踪
  • 你的 db 列类型定义是什么?你的 id 属性类型呢?无论如何,列的 Bigint 和 java 属性的 Long 都可以。
  • @mprabhat 完成。它有一条消息说我以前没有看到“不支持嵌套事务”。不知道是什么意思?
  • @polypiel 抱歉,我不确定我是否理解这个问题。 MySQL 中的数据类型是 BIGINT(20),而 hibernate 配置就是我上面发布的所有内容。
  • 意识到“不支持嵌套事务”可能是另一个单独的异常引发,因为我试图在前一个事务失败时开始一个新事务。所以它在这种情况下不相关。

标签: java mysql hibernate


【解决方案1】:

当您使用saveOrUpdate() 方法时如果对象的id 是nullupdate,如果它是任何其他值,hibernate 会触发插入查询。 我可以看到代码, Person person = new Person(1,"John","Doe");id 设置为1 并调用saveOrUpdate() 方法。我假设 id 1 没有条目,因此会引发错误。

要使其正常工作,您需要进行以下更改。

  1. id的类型从long更改为Long(包装类,使其可以支持null)。

  2. 编写构造函数new Person("John","Doe"); 并保存该对象。

为事务数据保留&lt;generator class="assigned"/&gt; 不是一个好主意。相反,您应该坚持使用native,就像您首先尝试的那样。

我觉得这是解决您最初问题的一种更简洁的方法,即使您已经找到了替代解决方案。

【讨论】:

  • 谢谢。您的假设是正确的,即在SaveOrUpdate 之前没有id=1 的先前记录。我尝试根据您的建议将类类型更改为Long,但如果我将生成器设置为native,它会恢复到相同的错误。我不明白你在构造函数中省略 id 的第二点? id 不是自动生成的 id,因此我需要能够将其设置为特定值。
  • 我的意思是让您的数据库选择 ID,并且在保存时不要将 id 硬编码为一直。从选项here 中选择如何做到这一点。
  • 好的,知道了。在我的实际场景中,id 是由外部服务提供的,因此需要保持不变,所以我不能让数据库决定。如果我只是将类类型更改为Long 并保留一个采用Long 的构造函数,我会得到原始异常。这是预期的还是我误解了其他东西?您提到了使用 generator=assigned 进行交易的风险。有什么风险?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-04-06
  • 2017-01-03
  • 1970-01-01
  • 1970-01-01
  • 2013-12-09
相关资源
最近更新 更多