hibernate3+jpa进行sql查询的一个框架bug解决

背景:

hibernate已经是众所周知的全自动ORM框架,使用起来非常便捷,但是有的时候自己也需要写sql进行查询(为什么不用mybatis?我进公司的时候框架里边就用了hibernate,由于业务不断扩大,想改造成mybatis代价很大);在使用hibernate进行sql查询时候,出现Column ‘xxx’ not fund异常;

问题分析:

1、sql有问题,查询的字段数据库没有?

将执行的sql贴到mysql客户端执行无异常,证明不是sql的问题

2、hibernate3自带bug?

进行hibernate源码查阅,整个程序执行步骤如下:

第一步:通过EntityManager的createNativeQuery(sql)方法获取Query对象

113950_gVLq_2893762.png

第二步:将获取到的Query设置查询参数,然后调用query.getResultList()方法,此方法真正进行查询处理,内部实现如下:

a、通过第一步源码得知返回的是实现Query接口的QueryImpl对象,所以直接查看QueryImpl里面的getResultList()方法:

114443_pi4Y_2893762.png

query对象是第一步的时候QueryImpl实例化传入进来的,得知query其实就是SqlQuery:

114615_luM6_2893762.png

SqlQuery是个接口,由图可知,SqlQuery的实现就只有SqlQueryImpl:

120423_HOqc_2893762.png

b、进入到sqlQueryImpl的list()方法,得知调用的是getSession().list(spec, getQueryParameters(namedParams))方法

120658_PFSz_2893762.png

getSession()返回的是SessionImpl对象,进入SessionImpl的list(NativeSQLQuerySpecification spec, QueryParameters queryParameters)方法:

122416_DcWx_2893762.png

进入listCustomQuery方法:

122637_I7ee_2893762.png

CustomLoader是真正处理查询的类,调用关系如图:

123514_Zc7W_2893762.png

buildResultRow方法才是正在将resultSet一行数据转成结果,源码:

123651_eMcT_2893762.png

由源码可知,最后通过columnProcessors来处理,columnProcessors是CustomLoader.ResultColumnProcessor数组

124614_qzuN_2893762.png

ResultColumnProcessor的实现有两个,通过调试本次查询使用的是ScalarResultColumnProcessor类

125100_9WVB_2893762.png

最终核心执行方法:

125006_F3tE_2893762.png

performDiscovery:这个方法是获取查询字段的列名

extract:这个方法核心调用是根据列名从resultSet里面获取值,并根据数据中的字段类型自动转型

到这里问题出现的原因差不多就知道了:

由于是根据列名从resultSet获取值,但是sql里面存在别名的字段情况下,是获取不到改字段的;比如:

使用SELECT name as uname FROM user进行查询,列名是:name,别名是uname,如果使用resultSet.getObject(“name”)会报找不到列的错误,resultSet.getObject(“uname”)是可以正确获取到值

解决办法:

重新实现CustomLoader,继承CustomLoader并重写getResultColumnOrRow方法;

注意:由于CustomLoader是直接在SessionImpl的listCustomQuery方法里面直接实例化的,并没有提供改类的set方法由调用者传入,所以必须实现自定义SessionImpl实现

如有问题,请多多指教,谢谢

 

 

转载于:https://my.oschina.net/jwang/blog/827763

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值