日期:2014-05-16  浏览次数:20424 次

JDBC中,如何快速的获取结果集结构?

问题描述:

对于给定的SQL语句(SELECT),以及数据库信息(url,用户名,密码),如何快速获取SQL语句执行后返回的结果集的结构?比如包含的字段个数,包含的字段名称以及Java类型

?

小试牛刀:

第一眼看上去,问题确实很简单。任何对JDBC有一定了解的人,都会很容易给出下面的方案:

1、根据数据库信息,创建数据库Connection;

2、利用Connection和SQL语句,创建一个PreparedStatement;

3、执行PreparedStatement,获取结果集ResultSet;

4、通过ResultSet获取ResultSetMetaData,所有的信息都在ResultSetMetaData中。

代码很快写好了,测试一下吧,select * from table,ok没问题。

?

问题出现了:

代码顺利提交,正寻思休息一下,测试姐姐满头大汗的过来了:

帮我看看,我的页面怎么死住了?

怎么可能?我测试可是没问题的啊。是不是你的SQL写的不对啊。

没有啊,我写的也是select * from table。

?

经过一番查找,终于发现问题了:

我的table里,只有100条数据,测试姐姐的表,居然有5,000,000条数据,select *一次,居然一分钟,IE长时间等不到返回,直接就死住了。

?

问题的症结:

其实上面的方案还是正确的,问题主要是查询出来的数据太多,导致数据库长时间不返回,页面就死掉了。

如果有一种方案,能保证查询出来的数据很少,最好是一条记录都没有,就好了。反正我要的是结果集的结构,不关心有没有数据。

将SQL修改成:select * from table where 1=2,用测试姐姐的数据表试试,页面马上就出来了,看来这招可行。

?

再次尝试:

经过上面的尝试,初步确定了第二个方案:对于用户给定的SQL,拼接上一个永假式,再执行拼接后的SQL。因为拼接了永假式,所以不会有满足条件的数据,这样就可以快速的获取到ResultSet了。

对于用户给定的SQL语句,可以采用以下方式处理:

1、直接拼接永假式,如:select * from table,拼接后:select * from table where 1=2

2、如果上面的方式不成立,再次尝试,如: select * from table t where t.id > 100,可以拼结成:select * from table t where t.id > 100 AND 1 = 2

3、如果第2种方式依然不行,直接执行SQL。

?

可惜,这种方案能依然存在问题:

1、最坏的情况下,需要查询三次数据库;

2、如果第3步查询的结果集中,包含数据过大,页面依然会假死。

?

最终解决:

吃午饭的时候,和DBA简单的聊了一会儿,到底是DBA,一句话点醒梦中人:用子查询。

?

最终得到了方案,很简洁:

对于用户输入的SQL,转化为以下形式:

?????? SELECT * FROM (?SQL )? TEST_SQL_TEMP WHERE 1 = 2

让我们进一步看一下:?

1、我们将SQL作为一个子查询,起了一个别名 TEST_SQL_TEMP ;

2、然后我们基于TEST_SQL_TEMP进行查询,用SELECT * 可以保证结果集与直接执行SQL得到的结果集结构相同;

3、最后别忘了的永假式 WHERE 1=2

?

?

?

声明:

文章来自于ITeye,欢迎访问我的博客:xiaoyu1985ban.iteye.com

ITeye文章版权属于作者,受法律保护。没有作者书面许可不得转载。若作者同意转载,必须以超链接形式标明文章原始出处和作者。

1 楼 唔系好人 2012-05-22  
2 楼 kensunhu 2012-05-23  
请问下:
select * from ( select * from table_name) TEST_SQL_TEMP  where 1=2
若先执行select * from table_name查询的话,是否也会先把所有记录查出来呢?
3 楼 xiaoyu1985ban 2012-05-23  
kensunhu 写道
请问下:
select * from ( select * from table_name) TEST_SQL_TEMP  where 1=2
若先执行select * from table_name查询的话,是否也会先把所有记录查出来呢?


很好的问题。

select * from table_name,在执行时,查询计划包括两个部分:

第一部分:TABLE ACCESS FULL 耗时:62290
第二部分:SELECT STATEMENT, GOAL = ALL_ROW,耗时 62290

select * from ( select * from table_name) TEST_SQL_TEMP  where 1=2  在执行时,查询计划包括三个部分:
第一部分:TABLE ACCESS FULL 耗时:62290
第二部分:Filter(WHERE条件)
第三部分:SELECT STATEMENT, GOAL = ALL_ROW,耗时 0

添加永假式的主要作用,是降低了SELECT STATEMENT部分的时间,但是TABLE ACCESS FULL这部分的时间,是不能省略的。

4 楼 唔系好人 2012-05-24  
xiaoyu1985ban 写道
kensunhu 写道
请问下:
select * from ( select * from table_name) TEST_SQL_TEMP  where 1=2
若先执行select * from table_name查询的话,是否也会先把所有记录查出来呢?


很好的问题。

select * from table_name,在执行时,查询计划包括两个部分:

第一部分:TABLE ACCESS FULL 耗时:62290
第二部分:SELECT STATEMENT, G