Hibernate保存到数据库后,对象的时间戳出错

8

我是Hibernate的新手,正在处理使用Hibernate的Web项目。

我有一个对象叫做area,它有一个日期对象(java.sql.Timestamp)属性modifiedDate。当我创建一个新对象时,modifieDate为null,在我的类中调用getHibernateTemplate().saveOrUpdate(area);,这个类继承自org.springframework.orm.hibernate3.support.HibernateDaoSupport,此时它被设置为当前时间戳并保存在数据库中。在数据库中,它被保存为datetime

我的问题是,大多数情况下,该对象更新的日期与保存在数据库中的日期相差1毫秒,这会导致异常,如果尝试重新加载页面而进行任何更新:

an org.hibernate.StaleObjectStateException: Row was updated or deleted by another transaction (or unsaved-value mapping was incorrect)

从数据库中获取对象时,日期正确没有问题,只有在创建对象时才会出现错误的值。

是否有办法在SaveOrUpdate方法中获取正确的modifiedDate?

如果需要的话,映射使用<timestamp name="modifiedDate" column="ModifiedDate"/>,所有测试都在本地主机上运行,并且所有内容都在同一台机器上运行。

我已经有一个解决方法了,在saveOrUpdate之后调用getHibernateTemplate().refresh(area)可以获取正确的时间戳,但是我仍然想知道是否有办法在saveOrUpdate中获取正确的modifiedDate。


也许它将纳秒四舍五入到多一毫秒? - Luciano
@Luciano 这是一个非常好的可能性,但我该如何修复它,为什么它不会在任何地方产生相同的舍入误差? - Blem
如果您想尝试,请在modifiedDate字段中使用Timestamp.setNanos(0); 我不知道您使用的是哪种DB,但如果该datetime列具有毫秒精度,则应将ModifiedDate从Timestamp更改为java.util.Date. - Luciano
当我进行步进时,我遇到了一个时间戳以.945结尾,在数据库中以.947结尾的情况。因此不太确定它是否是一个舍入误差,现在采用了简单的解决方案,即一旦对象已保存,我就将其丢弃并从数据库中获取一个新对象。但仍然想知道为什么会发生这种情况。 - Blem
@PaulMorie MSSQL,我想说的是2008 R2,但我现在没有它。 - Blem
请查看我的答案;SQL Server上的datetime会四舍五入毫秒值。 - Paul Morie
1个回答

4

我的理论:

问题出在你在数据库端使用的数据类型比Java端使用的数据类型精度低,因此你持久化到数据库中的值会在生成特定于数据库的SQL语句时失去精度(或按某种方式四舍五入,见下文)。以下是如何确定:

  1. 记住,Hibernate通过生成SQL语句在数据库中执行。要诊断类似这样的Hibernate映射问题,您需要查看正在执行的SQL以准确了解正在发生的情况。

  2. 为Hibernate开启“显示SQL”设置。这将导致Hibernate转储在数据库上执行的原始SQL。

  3. 检查您测试的日志记录。实现类的toString并将该值记录下来以与Hibernate生成的INSERT进行比较会很有帮助。 SQL语句中的值是否与Java时间戳字段的值匹配?

您应该检查数据库的DATETIME类型的精度设置。例如,在SQL Server上,DATETIME实现毫秒舍入(请参阅“准确性”字段),从而有效地导致毫秒值的精度丢失。根据您的精度需求,您将希望更改列映射到的Java类型或更改数据库中列的类型。


1
我有一个类似的问题,你的精准评论解决了我的难题。我正在使用SQL Server,但没有指定使用哪种方言。似乎Hibernate选用了2005方言,并为我的java Date对象创建了DATETIME列。在创建记录时,我一直遇到StaleObjectStateExceptions,让我相当沮丧。将方言切换到2008+,并将所有列从DATETIME更改为DATETIME2后,问题得以解决。谢谢! - Andre
太棒了,安德烈! - Paul Morie

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接