項目中使用統一的接口,調用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的架構還不熟悉,在沒有大量的測試資源的狀況下,感受不太靠譜。