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的架构还不熟悉,在没有大量的测试资源的状况下,感受不太靠谱。

相关文章
相关标签/搜索