问题描述:
对于给定的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文章版权属于作者,受法律保护。没有作者书面许可不得转载。若作者同意转载,必须以超链接形式标明文章原始出处和作者。