hibernate中使用sql查詢,時間類型丟失時分秒

項目中使用統一的接口,調用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 );


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 );
。。。
}

其中 getResultSet會對映射關係進行一個初始化。這裏,hibernate的loader維持了一個本身的ResultRowProcessor,其中包含查詢結果的映射解析器ScalarResultColumnProcessor。

(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的架構還不熟悉,在沒有大量的測試資源的狀況下,感受不太靠譜。

相關文章
相關標籤/搜索