hibernate中使用sql查询,时间类型丢失时分秒

项目中使用统一的接口,调用hibernate进行sql查询。

使用SqlQuery查询,返回结果为List<Map<String,Object>>。发现结果中的时间只有年月日,没有时分秒。

查询资料后知道,造成这个现象的原因是使用的oracle10g的驱动ojdbc14.jar造成的。如果使用9i或者11g的驱动则没有这个问题。

在看到这个原因后,我对hibernate的数据映射原理产生了兴趣,跟踪源代码看到了问题的最终产生来源。

(1)SqlQuery的list()方法默认调用以下

List org.hibernate.impl.SessionImpl.listCustomQuery(CustomQuery customQuery, QueryParameters queryParameters) throws HibernateException

(2)在这里创建了CustomLoader loader = new CustomLoader( customQuery, getFactory() );

最终调用loader.list(this, queryParameters);

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


你可能感兴趣的:(sql,源码,Hibernate,日期,映射)