我在 stackoverflow 上进行了很多搜索,发现将 java.util.Date 映射到 SQL 数据库通常会导致问题,可能的解决方案是
- 创建自己的(使用 jodatime)休眠用户类型
- 在持久化 db 之前截断 java.util.Date(失去精度)
然而,在我见过的所有情况下,问题是当保存日期时,最后一个字段(例如毫秒)丢失了(例如 000)。就我而言,它有点不同,请考虑以下代码:
public class TestDateTime implements Serializable {
private long id;
private Date created;
private Calendar published;
public TestDateTime(Date created, Date published) {
this.created = created;
this.published = GregorianCalendar.getInstance();
this.published.setTime(published);
}
}
<class name="TestDateTime" table="TestDateTime">
<id name="id" type="long" column="id">
<generator class="identity" />
</id>
<property name="created" column="created"/>
<property name="published" column="published"/>
</class>
private void testSaveDate(HibernateTemplate hibernateTemplate) {
long time = 1357747095488l;
TestDateTime tdt = new TestDateTime(new Date(time), new Date(time));
System.out.println("Before saving created:" + tdt.getCreated().getTime() + " (" + tdt.getCreated() + ")"
+ ", published:" + tdt.getPublished().getTime().getTime() + " (" + tdt.getPublished().getTime() + ")");
Serializable id = hibernateTemplate.save(tdt);
TestDateTime saved = hibernateTemplate.get(TestDateTime.class, id);
System.out.println("After saving created:" + saved.getCreated().getTime() + " (" + saved.getCreated() + ")"
+ ", published:" + saved.getPublished().getTime() + " (" + saved.getPublished() + ")");
}
在控制台上产生以下输出:
[INFO] Before saving created:1357747095488 (Wed Jan 09 16:58:15 CET 2013), published:1357747095488 (Wed Jan 09 16:58:15 CET 2013)
[INFO] Hibernate: insert into TestDateTime (created, published) values (?, ?)
[INFO] Hibernate: select testdateti0_.id as id42_0_, testdateti0_.created as created42_0_, testdateti0_.published as published42_0_ from TestDateTime testdateti0_ where testdateti0_.id=?
[INFO] After saving created:1357747095487 (2013-01-09 16:58:15.487), published:Wed Jan 09 16:58:15 CET 2013 (java.util.GregorianCalendar[time=1357747095487,areFieldsSet=true,areAllFieldsSet=true,lenient=true,zone=sun.util.calendar.ZoneInfo[id="Europe/Berlin",offset=3600000,dstSavings=3600000,useDaylight=true,transitions=143,lastRule=java.util.SimpleTimeZone[id=Europe/Berlin,offset=3600000,dstSavings=3600000,useDaylight=true,startYear=0,startMode=2,startMonth=2,startDay=-1,startDayOfWeek=1,startTime=3600000,startTimeMode=2,endMode=2,endMonth=9,endDay=-1,endDayOfWeek=1,endTime=3600000,endTimeMode=2]],firstDayOfWeek=2,minimalDaysInFirstWeek=4,ERA=1,YEAR=2013,MONTH=0,WEEK_OF_YEAR=2,WEEK_OF_MONTH=2,DAY_OF_MONTH=9,DAY_OF_YEAR=9,DAY_OF_WEEK=4,DAY_OF_WEEK_IN_MONTH=2,AM_PM=1,HOUR=4,HOUR_OF_DAY=16,MINUTE=58,SECOND=15,MILLISECOND=487,ZONE_OFFSET=3600000,DST_OFFSET=0])
因此,将日期保存到 SQL 服务器后,它将 1ms 从1357747095488更改为1357747095487。这是 SQL Server 日期时间类型的预期行为吗?
此外,我不得不提一下,Date 对象是由 JackRabbit 在签入期间创建的,因此我无法在 JackRabbit 中截断该日期,以使其与存储在 SQL Server 中的值同步。
问题是,在我的应用程序中,我必须比较这些日期,一些来自 JackRabbit,一些来自数据库(最初也是由 jackrabbit 创建的)。由于 sql server 中的日期版本与 JackRabbit 中的不同,我无法正确比较它们。
对我来说最好的解决方案是什么,即多数据库兼容(我们同时使用 MySql 和 MsSql 2008 R2)。是否有标准方法将 java.util.Date 映射到 bigint 列,以便我可以自己存储 long 值?或者我应该创建我的用户类型?这是一个坏主意,因为我仍然可以比较查询中的 long(我假设 Hibernate 也有正确的映射)