Hibernate映射中date类型和java.util.Date变Timestamp的问题

小宁很淡定 2014-07-16 05:31:20
实体类和映射都是java.util.Date类型,从数据库获取到对象时,Date类型自动变成java.sql.Timestamp,但是经过试验,其他不变,将Hibernate映射文件中的类型改为date或java.sql.Date时就不会这样,这是为什么?

数据库:sqlserver10;
框架采用SSH:(struts2.3.14,spring3.2.2,hibernate3.3.0)

Hibernate映射文件:
<property name="dateTest" type="java.sql.Date" column=" dateTest "/>

数据库中类型为:datetime

Pojo中属性:
import java.util.Date;
private Date dateTest;
//get,set略.

Action中:根据class和id获取对象:
pojo = (Pojo) PojoService.findEntityById(Pojo.class, id);//根据id获取对象

findEntityById具体实现:
getHibernateTemplate().get(paramClass, paramSerializable);

起因是定义了struts2类型转换器,用于日期和时间的显示:
java.util.Date=org.lama.tools.converter.DateConverter
java.sql.Date=org.lama.tools.converter.DateConverter
java.sql.Timestamp=org.lama.tools.converter.TimestampConverter

但是发现上面那个java.util.Date类型的dateTest属性在页面上居然以yyyy-MM-dd HH:mm:ss格式显示的,百思不得其解,后将get方法进行修改加入了以下:
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
return sdf.parse(sdf.format(dateTest));
问题是解决了,但是并不完美,所以并没有采用这种方法,毕竟项目中很多的Date类型,要每个get方法都改会加大工作量.

设置断点跟踪了一下,发现从数据库中读取出的dateTest是java.sql.Timestamp类型,并没有通过我定义的用于类型转换的DateConverter类,所以页面显示的是yyyy-MM-dd HH:mm:ss,将dateTest的hibernate映射类型改为date或java.sql.Date后,页面显示正常,变为yyyy-MM-dd,跟踪发现取到的类型是java.sql.Date,由于这个类是java.utile.Date的子类,所以get,set时并没有什么问题,而将页面中的值修改为yyyy-MM-dd格式后,提交表单进行保存后,类型又变为了java.util.Date,反复保存也并没有问题,数据库中的值也正常.

再将hibernate映射中的类型改为java.util.Date, 页面显示的是yyyy-MM-dd HH:mm:ss, 将页面中的值修改为yyyy-MM-dd格式后,提交表单进行保存后,类型又变为了java.util.Date,反复保存也同样没有问题,数据库中的值也正常.

所以我想是不是因为数据库中datetime类型所导致的,尝试将数据库中字段类型改为date类型,悲剧发生了,直接在获取对象的时候报以下异常:
org.springframework.jdbc.UncategorizedSQLException: Hibernate operation: could not load an entity: [org.lama.buildtree.pojo.Device#24]; uncategorized SQLException for SQL [select device0_.ID as ID17_0_, device0_.deviceName as deviceName17_0_, device0_.DeviceVersion as DeviceVe3_17_0_, device0_.DateInProduced as DateInPr4_17_0_, device0_.UseAge as UseAge17_0_, device0_.CostPrice as CostPrice17_0_, device0_.Remark as Remark17_0_, device0_.Status as Status17_0_, device0_.buildId as buildId17_0_, device0_.SectionId as SectionId17_0_ from Device device0_ where device0_.ID=?]; SQL state [null]; error code [0]; An SQLException was provoked by the following failure: java.lang.IllegalArgumentException: Timestamp format must be yyyy-mm-dd hh:mm:ss[.fffffffff]; nested exception is java.sql.SQLException: An SQLException was provoked by the following failure: java.lang.IllegalArgumentException: Timestamp format must be yyyy-mm-dd hh:mm:ss[.fffffffff]
at org.springframework.jdbc.support.AbstractFallbackSQLExceptionTranslator.translate(AbstractFallbackSQLExceptionTranslator.java:83)
Caused by: java.sql.SQLException: An SQLException was provoked by the following failure: java.lang.IllegalArgumentException: Timestamp format must be yyyy-mm-dd hh:mm:ss[.fffffffff]
at com.mchange.v2.sql.SqlUtils.toSQLException(SqlUtils.java:106)
at com.mchange.v2.sql.SqlUtils.toSQLException(SqlUtils.java:65)
at com.mchange.v2.sql.SqlUtils.toSQLException(SqlUtils.java:62)
at com.mchange.v2.c3p0.impl.NewPooledConnection.handleThrowable(NewPooledConnection.java:432)
at com.mchange.v2.c3p0.impl.NewProxyResultSet.getTimestamp(NewProxyResultSet.java:3408)
at org.hibernate.type.TimestampType.get(TimestampType.java:53)
at org.hibernate.type.NullableType.nullSafeGet(NullableType.java:184)
at org.hibernate.type.NullableType.nullSafeGet(NullableType.java:173)
at org.hibernate.type.AbstractType.hydrate(AbstractType.java:105)
at org.hibernate.persister.entity.AbstractEntityPersister.hydrate(AbstractEntityPersister.java:2124)
at org.hibernate.loader.Loader.loadFromResultSet(Loader.java:1404)
at org.hibernate.loader.Loader.instanceNotYetLoaded(Loader.java:1332)
at org.hibernate.loader.Loader.getRow(Loader.java:1230)
at org.hibernate.loader.Loader.getRowFromResultSet(Loader.java:603)
at org.hibernate.loader.Loader.doQuery(Loader.java:724)
at org.hibernate.loader.Loader.doQueryAndInitializeNonLazyCollections(Loader.java:259)
at org.hibernate.loader.Loader.loadEntity(Loader.java:1881)
at org.hibernate.loader.entity.AbstractEntityLoader.load(AbstractEntityLoader.java:71)
at org.hibernate.loader.entity.AbstractEntityLoader.load(AbstractEntityLoader.java:65)
at org.hibernate.persister.entity.AbstractEntityPersister.load(AbstractEntityPersister.java:3072)
at org.hibernate.event.def.DefaultLoadEventListener.loadFromDatasource(DefaultLoadEventListener.java:434)
at org.hibernate.event.def.DefaultLoadEventListener.doLoad(DefaultLoadEventListener.java:415)
at org.hibernate.event.def.DefaultLoadEventListener.load(DefaultLoadEventListener.java:165)
at org.hibernate.event.def.DefaultLoadEventListener.proxyOrLoad(DefaultLoadEventListener.java:223)
at org.hibernate.event.def.DefaultLoadEventListener.onLoad(DefaultLoadEventListener.java:126)
at org.hibernate.impl.SessionImpl.fireLoad(SessionImpl.java:905)
at org.hibernate.impl.SessionImpl.get(SessionImpl.java:842)
at org.hibernate.impl.SessionImpl.get(SessionImpl.java:835)
at org.springframework.orm.hibernate3.HibernateTemplate$1.doInHibernate(HibernateTemplate.java:519)
at org.springframework.orm.hibernate3.HibernateTemplate.doExecute(HibernateTemplate.java:406)
... 105 more
Caused by: java.lang.IllegalArgumentException: Timestamp format must be yyyy-mm-dd hh:mm:ss[.fffffffff]
at java.sql.Timestamp.valueOf(Timestamp.java:185)
at net.sourceforge.jtds.jdbc.Support.convert(Support.java:387)
at net.sourceforge.jtds.jdbc.JtdsResultSet.getTimestamp(JtdsResultSet.java:1160)
at net.sourceforge.jtds.jdbc.JtdsResultSet.getTimestamp(JtdsResultSet.java:1312)
at com.mchange.v2.c3p0.impl.NewProxyResultSet.getTimestamp(NewProxyResultSet.java:3394)
... 130 more


(异常部分有删减)异常大体意思说的就是Timestamp类型的解析错误,可见不论数据库中类型是什么,获取到action中的对象属性类型都是java.util.Timestamp,所以经过了这些尝试后,发现Hibernate映射文件中的类型只能写成java.sql.Date了,虽然date也可以,但是一直习惯都是使用java类型来定义,网上也说hibernate和java类型混搭不好,但我试了一下,也没有发现会有什么问题.

所以,我不明白的是,为什么hibernate会自动将java.util.Date类型映射转换成java.sql.Timestamp而不是java.util.Date呢?

第一次发帖,也不知道发这对不对...
...全文
18188 12 打赏 收藏 转发到动态 举报
AI 作业
写回复
用AI写文章
12 条回复
切换为时间正序
请发表友善的回复…
发表回复
  • 打赏
  • 举报
回复
引用 5 楼 wlwlwlwl015 的回复:
小伙子,我把这个问题给你讲清楚,也算对得起你给我丢的板砖了。 ----------------------------------------------------------------------------------------- 首先,hibernate是通过数据库来映射实体,所以我们是根据数据库的字段类型,来决定我们实体Bean的映射类型。 你说了,数据库中类型为:datetime,那么在不出错的情况下(你没有指定错误的类型),数据肯定就是 yyyy-MM-dd HH:mm:ss的格式了。 java.util.Date是JDBC API中的 java.sql.Date, java.sql.Time 和 java.sql.Timestamp的父类,也就是说,你把实体的属性定义为java.util.Date,并且不指定映射文件的中属性的type,那么这将是一个万金油的配置,因为它可以向下转型为任意的类型,也就是说,实体Bean中的时间类型应该永远都是java.util.Date,映射文件不设置,这样一般便不会出问题。但是推荐还是设置映射文件的类型,这样效率高一些,下面结合你的问题给你讲讲: 1.但是发现上面那个java.util.Date类型的dateTest属性在页面上居然以yyyy-MM-dd HH:mm:ss格式显示的,百思不得其解 因为你数据库定义的类型是datetime,datetime类型数据的格式本来就是“年月日时分秒”,刚说了是根据数据库的字段类型来决定映射类型的,所以你的定义的时间类型,hibernate都会帮你转换成正确的类型,就像你不配置type,还会帮你自动装配,是一个道理。 但是发现上面那个java.util.Date类型的dateTest属性在页面上居然以yyyy-MM-dd HH:mm:ss格式显示的,百思不得其解,后将get方法进行修改加入了以下: SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd"); return sdf.parse(sdf.format(dateTest)); 问题是解决了,但是并不完美 你表面上问题是解决了,因为你只看的是页面如何显示,我告诉你你这只是把datetime的时间格式化显示了一下而已,不是说解决了,你根本没弄明白问题的所在。 。 设置断点跟踪了一下,发现从数据库中读取出的dateTest是java.sql.Timestamp类型,并没有通过我定义的用于类型转换的DateConverter类 ORM映射和你这Struts转换器可以说没有一毛钱关系,Struts的作用是什么?是搭建了一个MVC框架,控制请求从哪进从哪出。实体和数据库的映射是hibernate提前就规定好的,就像KFC的套餐,人家定好,你只用买,而不是说你去买的时候你自己组装套餐。因为你数据库是datetime类型的,符合这个类型的只能是java.sql.TimeStamp,hibernate会替你转换好,这才是hibernate的强大之处,即使你不懂,你也可以用。 你对时间的理解还停留在什么页面的显示,时间的格式什么的,各种概念模糊,什么转换成java.util.Date?这是java的时间类型!可以表示任意格式的时间。 我不想回答这种问题就是超浪费时间。
引用 5 楼 wlwlwlwl015 的回复:
小伙子,我把这个问题给你讲清楚,也算对得起你给我丢的板砖了。 ----------------------------------------------------------------------------------------- 首先,hibernate是通过数据库来映射实体,所以我们是根据数据库的字段类型,来决定我们实体Bean的映射类型。 你说了,数据库中类型为:datetime,那么在不出错的情况下(你没有指定错误的类型),数据肯定就是 yyyy-MM-dd HH:mm:ss的格式了。 java.util.Date是JDBC API中的 java.sql.Date, java.sql.Time 和 java.sql.Timestamp的父类,也就是说,你把实体的属性定义为java.util.Date,并且不指定映射文件的中属性的type,那么这将是一个万金油的配置,因为它可以向下转型为任意的类型,也就是说,实体Bean中的时间类型应该永远都是java.util.Date,映射文件不设置,这样一般便不会出问题。但是推荐还是设置映射文件的类型,这样效率高一些,下面结合你的问题给你讲讲: 1.但是发现上面那个java.util.Date类型的dateTest属性在页面上居然以yyyy-MM-dd HH:mm:ss格式显示的,百思不得其解 因为你数据库定义的类型是datetime,datetime类型数据的格式本来就是“年月日时分秒”,刚说了是根据数据库的字段类型来决定映射类型的,所以你的定义的时间类型,hibernate都会帮你转换成正确的类型,就像你不配置type,还会帮你自动装配,是一个道理。 但是发现上面那个java.util.Date类型的dateTest属性在页面上居然以yyyy-MM-dd HH:mm:ss格式显示的,百思不得其解,后将get方法进行修改加入了以下: SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd"); return sdf.parse(sdf.format(dateTest)); 问题是解决了,但是并不完美 你表面上问题是解决了,因为你只看的是页面如何显示,我告诉你你这只是把datetime的时间格式化显示了一下而已,不是说解决了,你根本没弄明白问题的所在。 。 设置断点跟踪了一下,发现从数据库中读取出的dateTest是java.sql.Timestamp类型,并没有通过我定义的用于类型转换的DateConverter类 ORM映射和你这Struts转换器可以说没有一毛钱关系,Struts的作用是什么?是搭建了一个MVC框架,控制请求从哪进从哪出。实体和数据库的映射是hibernate提前就规定好的,就像KFC的套餐,人家定好,你只用买,而不是说你去买的时候你自己组装套餐。因为你数据库是datetime类型的,符合这个类型的只能是java.sql.TimeStamp,hibernate会替你转换好,这才是hibernate的强大之处,即使你不懂,你也可以用。 你对时间的理解还停留在什么页面的显示,时间的格式什么的,各种概念模糊,什么转换成java.util.Date?这是java的时间类型!可以表示任意格式的时间。 我不想回答这种问题就是超浪费时间。
特地给这个回答一个赞,这是今天看到关于这个问题最好的回答!!!
月夜轻飞雪 2015-06-15
  • 打赏
  • 举报
回复
额,原来hbm中有一个日期类型写成了string。。。。。。
月夜轻飞雪 2015-06-15
  • 打赏
  • 举报
回复
借个贴哈:用hibernate封装的save保存对象时报错:ora-01861 文字与格式不匹配这个错,数据库类型date,实体java.util.date,有人说是配置文件里的 type="date" 改成type="timestamp",,但是我改了没有作用。大神们怎么搞啊
卡特 2015-06-06
  • 打赏
  • 举报
回复
引用 5 楼 wlwlwlwl015 的回复:
小伙子,我把这个问题给你讲清楚,也算对得起你给我丢的板砖了。
-----------------------------------------------------------------------------------------
首先,hibernate是通过数据库来映射实体,所以我们是根据数据库的字段类型,来决定我们实体Bean的映射类型。
你说了,数据库中类型为:datetime,那么在不出错的情况下(你没有指定错误的类型),数据肯定就是 yyyy-MM-dd HH:mm:ss的格式了。
java.util.Date是JDBC API中的 java.sql.Date, java.sql.Time 和 java.sql.Timestamp的父类,也就是说,你把实体的属性定义为java.util.Date,并且不指定映射文件的中属性的type,那么这将是一个万金油的配置,因为它可以向下转型为任意的类型,也就是说,实体Bean中的时间类型应该永远都是java.util.Date,映射文件不设置,这样一般便不会出问题。但是推荐还是设置映射文件的类型,这样效率高一些,下面结合你的问题给你讲讲:
1.但是发现上面那个java.util.Date类型的dateTest属性在页面上居然以yyyy-MM-dd HH:mm:ss格式显示的,百思不得其解
因为你数据库定义的类型是datetime,datetime类型数据的格式本来就是“年月日时分秒”,刚说了是根据数据库的字段类型来决定映射类型的,所以你的定义的时间类型,hibernate都会帮你转换成正确的类型,就像你不配置type,还会帮你自动装配,是一个道理。
但是发现上面那个java.util.Date类型的dateTest属性在页面上居然以yyyy-MM-dd HH:mm:ss格式显示的,百思不得其解,后将get方法进行修改加入了以下:
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
return sdf.parse(sdf.format(dateTest));
问题是解决了,但是并不完美

你表面上问题是解决了,因为你只看的是页面如何显示,我告诉你你这只是把datetime的时间格式化显示了一下而已,不是说解决了,你根本没弄明白问题的所在。

设置断点跟踪了一下,发现从数据库中读取出的dateTest是java.sql.Timestamp类型,并没有通过我定义的用于类型转换的DateConverter类
ORM映射和你这Struts转换器可以说没有一毛钱关系,Struts的作用是什么?是搭建了一个MVC框架,控制请求从哪进从哪出。实体和数据库的映射是hibernate提前就规定好的,就像KFC的套餐,人家定好,你只用买,而不是说你去买的时候你自己组装套餐。因为你数据库是datetime类型的,符合这个类型的只能是java.sql.TimeStamp,hibernate会替你转换好,这才是hibernate的强大之处,即使你不懂,你也可以用。

你对时间的理解还停留在什么页面的显示,时间的格式什么的,各种概念模糊,什么转换成java.util.Date?这是java的时间类型!可以表示任意格式的时间。
我不想回答这种问题就是超浪费时间。


你讲的很对哦;
首先java和数据库能直接存的几个时间都是 sql包下的几个时间,
所以楼主的最后的一个疑问就解决了
"所以,我不明白的是,为什么hibernate会自动将java.util.Date类型映射转换成java.sql.Timestamp而不是java.util.Date呢?"
数据库存进去,取出来的只能是sql下的类型,你用JDBC的话就知道了,你如果把util.Date直接放数据库是会报错的.因为Hibernate会帮你改类型,util包下的Date是所有sql时间的父类所以你的类里的UtilDate在不设置列映射的话不会报错,但是刚从数据库取出来肯定是sql类型的,
DateFormat只是把Date的显示格式化,
好吧 ,其实我也是个小白 就这么样吧
finemi 2015-06-06
  • 打赏
  • 举报
回复
注解@Temporal 可以改变数据库中具体映射的类型 比如@Temporal(TemporalType.DATE) 或者@Temporal(TemporalType.TIMESTAMP)
小灯光环 2014-07-17
  • 打赏
  • 举报
回复
小伙子,我把这个问题给你讲清楚,也算对得起你给我丢的板砖了。
-----------------------------------------------------------------------------------------
首先,hibernate是通过数据库来映射实体,所以我们是根据数据库的字段类型,来决定我们实体Bean的映射类型。
你说了,数据库中类型为:datetime,那么在不出错的情况下(你没有指定错误的类型),数据肯定就是 yyyy-MM-dd HH:mm:ss的格式了。
java.util.Date是JDBC API中的 java.sql.Date, java.sql.Time 和 java.sql.Timestamp的父类,也就是说,你把实体的属性定义为java.util.Date,并且不指定映射文件的中属性的type,那么这将是一个万金油的配置,因为它可以向下转型为任意的类型,也就是说,实体Bean中的时间类型应该永远都是java.util.Date,映射文件不设置,这样一般便不会出问题。但是推荐还是设置映射文件的类型,这样效率高一些,下面结合你的问题给你讲讲:
1.但是发现上面那个java.util.Date类型的dateTest属性在页面上居然以yyyy-MM-dd HH:mm:ss格式显示的,百思不得其解
因为你数据库定义的类型是datetime,datetime类型数据的格式本来就是“年月日时分秒”,刚说了是根据数据库的字段类型来决定映射类型的,所以你的定义的时间类型,hibernate都会帮你转换成正确的类型,就像你不配置type,还会帮你自动装配,是一个道理。
但是发现上面那个java.util.Date类型的dateTest属性在页面上居然以yyyy-MM-dd HH:mm:ss格式显示的,百思不得其解,后将get方法进行修改加入了以下:
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
return sdf.parse(sdf.format(dateTest));
问题是解决了,但是并不完美

你表面上问题是解决了,因为你只看的是页面如何显示,我告诉你你这只是把datetime的时间格式化显示了一下而已,不是说解决了,你根本没弄明白问题的所在。

设置断点跟踪了一下,发现从数据库中读取出的dateTest是java.sql.Timestamp类型,并没有通过我定义的用于类型转换的DateConverter类
ORM映射和你这Struts转换器可以说没有一毛钱关系,Struts的作用是什么?是搭建了一个MVC框架,控制请求从哪进从哪出。实体和数据库的映射是hibernate提前就规定好的,就像KFC的套餐,人家定好,你只用买,而不是说你去买的时候你自己组装套餐。因为你数据库是datetime类型的,符合这个类型的只能是java.sql.TimeStamp,hibernate会替你转换好,这才是hibernate的强大之处,即使你不懂,你也可以用。

你对时间的理解还停留在什么页面的显示,时间的格式什么的,各种概念模糊,什么转换成java.util.Date?这是java的时间类型!可以表示任意格式的时间。
我不想回答这种问题就是超浪费时间。
lsongiu86 2014-07-17
  • 打赏
  • 举报
回复
Timestamp 是 Date的子类,可以直接转成date使用
sxax 2014-07-17
  • 打赏
  • 举报
回复
最简单的方法就是不要用Data直接用String简单粗暴,将时间按照yyyy-MM-dd HH:ss:mm这样转成字符串 然后 保存到数据库中
小宁很淡定 2014-07-17
  • 打赏
  • 举报
回复
引用 1 楼 wlwlwlwl015 的回复:
hibernate的映射是根据数据库的字段类型来决定的,你的字段是datetime类型的,映射成实体肯定就是TimeStamp。 实体类和映射都是java.util.Date类型,你这样定义本身就是错误的,和数据库相关的时间你用java.util.Date不报错才怪。
我猜一定是帖子太长了 你没细看....如果按你所说,那么你可以将数据库改成date看看什么结果...
小灯光环 2014-07-16
  • 打赏
  • 举报
回复
hibernate的映射是根据数据库的字段类型来决定的,你的字段是datetime类型的,映射成实体肯定就是TimeStamp。 实体类和映射都是java.util.Date类型,你这样定义本身就是错误的,和数据库相关的时间你用java.util.Date不报错才怪。

81,122

社区成员

发帖
与我相关
我的任务
社区描述
Java Web 开发
社区管理员
  • Web 开发社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧