项目中使用统一的接口,调用hibernate进行sql查询。 java
使用SqlQuery查询,返回结果为List<Map<String,Object>>。发现结果中的时间只有年月日,没有时分秒。 web
查询资料后知道,形成这个现象的缘由是使用的oracle10g的驱动ojdbc14.jar形成的。若是使用9i或者11g的驱动则没有这个问题。 sql
在看到这个缘由后,我对hibernate的数据映射原理产生了兴趣,跟踪源代码看到了问题的最终产生来源。 session
(1)SqlQuery的list()方法默认调用如下 架构
List org.hibernate.impl.SessionImpl.listCustomQuery(CustomQuery customQuery, QueryParameters queryParameters) throws HibernateException oracle
(2)在这里建立了CustomLoader loader = new CustomLoader( customQuery, getFactory() ); app
最终调用loader.list(this, queryParameters); eclipse
(3)继续跟进,调用到CustomLoader 父类Loader的 函数
private List listIgnoreQueryCache(SessionImplementor session, QueryParameters queryParameters) {
return getResultList( doList( session, queryParameters ), queryParameters.getResultTransformer());
}
其中doListdoList( session, queryParameters )为查询结果集,并初次包装。 测试
(4)最终跟进到Loader的private List doQuery(
final SessionImplementor session,
final QueryParameters queryParameters,
final boolean returnProxies) throws SQLException, HibernateException 方法。在这里能够看到jdbc的一些操做了。
final PreparedStatement st = prepareQueryStatement( queryParameters, false, session );
final ResultSet rs = getResultSet( st, queryParameters.hasAutoDiscoverScalarTypes(), queryParameters.isCallable(), selection, session );
for ( count = 0; count < maxRows && rs.next(); count++ ) {
。。。
Object result = getRowFromResultSet(
rs,
session,
queryParameters,
lockModesArray,
optionalObjectKey,
hydratedObjects,
keys,
returnProxies
);
results.add( result );
。。。
}
(5)默认的映射解析函数为CustomLoader 的protected void autoDiscoverTypes(ResultSet rs)
Metadata metadata = new Metadata( getFactory(), rs );
。。。
for ( int i = 0; i < rowProcessor.columnProcessors.length; i++ ) {
rowProcessor.columnProcessors[i].performDiscovery( metadata, types, aliases );
}
默认的映射使用CustomLoader 的 内部类ScalarResultColumnProcessor。此处的Metadata为查询结果集的元数据,获得的类为oracle.jdbc.driver.OracleResultSetMetaData。继续向下看就能发现最终的错误缘由了。
(6)ScalarResultColumnProcessor中根据metadata获取的类型为date类型。而在ScalarResultColumnProcessor最终取值时调用的是DateTypeDescriptor.getExtractor方法。其中部分实现为
protected X doExtract(ResultSet rs, String name, WrapperOptions options) throws SQLException {
return javaTypeDescriptor.wrap( rs.getDate( name ), options );
}
由此能够看到,最终从rs中使用getDate方法获取值。如此获取的值就只有日期没有时间。
全部的过程都看完以后,能够说形成这个问题的缘由在于metadata中返回的数据类型为date了,按照getDate获取形成的丢失时间。
解决办法:
1.添加自定义映射
sqlQuery.addScalar(columnAlias, type);
2.sql语句中使用to_char,直接查询出字符再作其余操做。
3.获取链接是添加属性
prop.setProperty("oracle.jdbc.V8Compatible","true");
Connection connection=DriverManager.getConnection("jdbc:oracle:thin:@127.0.0.1:1521:orcl", prop);
正在尝试将这个参数添加到c3p0的配置文件中,尚未成功。
4.修改hibernate源码,没有尝试。对hibernate的架构还不熟悉,在没有大量的测试资源的状况下,感受不太靠谱。