`
xiaoyu1985ban
  • 浏览: 132963 次
  • 性别: Icon_minigender_1
  • 来自: 大连
社区版块
存档分类
最新评论

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

2
1
分享到:
评论
11 楼 junsure 2014-03-02  
其实这个解决方案还是存在问题的,加入传进来的sql是多表联合查询,含有重复的列的话,是查不出表结构的,只有当传递的sql查询出的列没有重复的,才是正确的实现,具体更通用的实现是什么样子,我正在纠结中,如果哪位有好的解决方案的话,请联系我,谢谢!!!!
qq:544754473
10 楼 junsure 2014-03-02  
其实这个解决方案还是存在问题的,加入传进来的sql是多表联合查询,含有重复的列的话,是查不出表结构的,只有当传递的sql查询出的列没有重复的,才是正确的实现,具体更通用的实现是什么样子,我正在纠结中,如果哪位有好的解决方案的话,请联系我,谢谢!!!!
qq:544754473
9 楼 kesideyu1989 2013-08-22  
select * from ( select top 1 * from demo_employee_source) sqltemp where 1 = 2
8 楼 xiaoyu1985ban 2012-05-30  
kensunhu 写道
通过你的实践说明了我的主观判断出错了。
只要你证明这两条SQL执行耗时一样,就可以用子查询方案。
select * from ( select * from demo_employee_source) sqltemp where 1 = 2
select * from ude.demo_employee_source where 1 = 2



呵呵,没事儿。

真心的感谢你的回复,相信经过这一番讨论,以后进来的人就更清楚了。

希望你继续关注我的博客。
7 楼 kensunhu 2012-05-29  
通过你的实践说明了我的主观判断出错了。
只要你证明这两条SQL执行耗时一样,就可以用子查询方案。
select * from ( select * from demo_employee_source) sqltemp where 1 = 2
select * from ude.demo_employee_source where 1 = 2



6 楼 xiaoyu1985ban 2012-05-25  
kensunhu 写道
SELECT * FROM ( SQL )  TEST_SQL_TEMP WHERE 1 = 2
优点:不会有数据返回给调用程序,减少了数据返回给程序的时间。
缺点:先执行的SQL,若表数据量巨大,查询全表扫描,依然会耗时很多,前台页面调用依然会假死。楼主可以验证下哦。本人认为嵌套查询还是没解决问题。

建议最好的解决方案是判断用户输入的SQL产生如下执行SQL:
SQL where 1=2   或
SQL and 1=2



十分感谢您的回复。
1、您说的那种方案,我已经尝试过了,但最后没有采用这种方案,具体原因您可以看文中“再次尝试”部分的内容。
2、关于子查询和直接拼接SQL谁耗时少的问题,我刚刚进行了验证。结果是两个SQL的执行计划是一样的。下面是验证的过程,跟您分享一下:

数据库:Oracle 11g
数据量:300万;
用户输入SQL: select * from demo_employee_source
第一个SQL(采用子查询方案拼接): select * from ( select * from demo_employee_source) sqltemp where 1 = 2第二个SQL (采用判断用户输入的方式拼接): select * from ude.demo_employee_source where 1 = 2
验证方式:直接在PL/SQL中,查看两个方案生成的SQL。
验证结果:两个SQL的执行计划是一样的。
5 楼 kensunhu 2012-05-25  
SELECT * FROM ( SQL )  TEST_SQL_TEMP WHERE 1 = 2
优点:不会有数据返回给调用程序,减少了数据返回给程序的时间。
缺点:先执行的SQL,若表数据量巨大,查询全表扫描,依然会耗时很多,前台页面调用依然会假死。楼主可以验证下哦。本人认为嵌套查询还是没解决问题。

建议最好的解决方案是判断用户输入的SQL产生如下执行SQL:
SQL where 1=2   或
SQL and 1=2
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, 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这部分的时间,是不能省略的。


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这部分的时间,是不能省略的。

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

相关推荐

    jdbc数据集生成器

    **jdbc数据集生成器**是一种实用工具,它能够根据通过JDBC(Java Database Connectivity)接口获取的数据集(ResultSet)自动生成HTML文档,通常以表格的形式展示。这种工具模仿了数据库的导出数据功能,使得开发者...

    封装jdbc,采用Map方式快速增删改数据库例子

    JDBC提供了一组接口和类,允许开发者在Java程序中执行SQL语句,处理结果集,以及管理数据库连接。通常,数据库操作包括以下几个步骤:加载驱动、建立连接、创建Statement或PreparedStatement对象、执行SQL、处理结果...

    JDBC教程

    - **Statement**: 用于执行静态SQL语句,获取结果集。 - **PreparedStatement**: 预编译的SQL语句,支持参数化查询,提高性能和安全性。 - **CallableStatement**: 用于调用存储过程的接口。 - **ResultSet**: 存储...

    C++操作MYSQL库类JDBC

    4. **结果集处理**:`ResultSet`类代表SQL查询的结果,提供遍历查询结果、获取单个列值或行数据的方法。 5. **异常处理**:类库应包含适当的异常处理机制,当发生错误时抛出异常,以便于程序捕获并处理。 6. **...

    非常全面JDBC资源

    1. **结果集处理**: `ResultSet`对象表示查询的结果,可以通过`next()`方法遍历行,通过列索引或列名获取数据。 2. **事务管理**: 使用`conn.setAutoCommit(false)`关闭自动提交,通过`conn.commit()`和`conn....

    java实现jdbc查询结果集result转换成对应list集合

    当我们通过JDBC执行SQL查询并获取结果集(ResultSet)时,通常我们需要将这些数据转换为更易于处理的数据结构,如List。本篇文章将详细讲解如何将ResultSet转换为对应的List集合。 首先,我们了解ResultSet对象。...

    JDBC实现MYSQL数据库迁徙

    通过JDBC,我们可以执行SQL语句,获取结果集,以及进行事务处理等操作。在数据库迁移中,我们需要利用JDBC连接源数据库和目标数据库,读取源数据库的数据,然后写入到目标数据库中。 MySQL是一款广泛使用的开源关系...

    jdbc_clickhouse.zip

    可以遍历这个结果集,获取每一行的数据。 6. **事务管理**:在JDBC中,可以使用`Connection`对象的`setAutoCommit()`方法控制事务。如果禁用自动提交,需要手动调用`commit()`或`rollback()`来提交或回滚事务。 7....

    jdbc连接 ldap jar 包

    5. **处理结果集**:对于查询操作,会返回一个`ResultSet`对象,可以通过迭代来获取查询结果。 6. **关闭资源**:最后,别忘了关闭`ResultSet`, `Statement`和`Connection`,以释放系统资源。 在实际应用中,JDBC ...

    jdbc连接mysql工具类

    总之,`jdbc连接mysql工具类`主要涉及JDBC API的使用,包括数据库连接、预编译的SQL语句(PreparedStatement)、结果集处理以及资源管理。这个工具类可以极大地简化数据库操作,提高代码的可维护性和复用性。通过...

    Apress.JDBC.Recipes.A.Problem.Solution.Approach.Sep.2005.pdf

    - **结果集管理**:学习如何使用ResultSet对象获取查询结果,包括数据类型转换、结果集滚动和元数据访问等高级技巧。 - **批处理操作**:介绍如何使用BatchUpdate操作提高数据插入、更新或删除的效率,减少网络往返...

    JDBC封装类

    描述:此文章将详细介绍一个用于简化Java中JDBC操作的封装类,该类通过提供一系列方法来加速数据库编程任务,包括建立数据库连接、执行查询、处理结果集以及执行更新操作。 ### 一、JDBC封装类概述 在Java开发中,...

    通用模板,JDBC 增删改查封转

    在JDBC中,查询的结果通常会返回一个ResultSet对象,我们需要遍历这个结果集来获取数据。ResultMaker可能提供了便利的方法,如将ResultSet转换成List、Map或者其他自定义的数据结构,方便业务层进行数据处理。这可以...

    JDBC课件,关于JDBC使用

    - **ResultSet类**:表示SQL查询的结果集,提供遍历查询结果的方法。 - **ResultSetMetaData类**:提供关于ResultSet列的信息,如列数量、名称、类型等。 - **DatabaseMetaData类**:提供了获取数据库元数据的方法,...

    JDBC简明学习教程

    通过JDBC,我们可以执行SQL语句、处理结果集、事务管理等。JDBC的核心组件包括DriverManager、Connection、Statement、PreparedStatement和ResultSet等。 ### 2. JDBC驱动程序 JDBC驱动程序是Java程序与数据库之间...

    sharding-jdbc开源分表框架整合mybatis-demo

    MyBatis避免了几乎所有的JDBC代码和手动设置参数以及获取结果集。MyBatis可以使用简单的XML或注解进行配置和原始映射,将接口和Java的POJOs(Plain Old Java Objects,普通的Java对象)映射成数据库中的记录。 **整合...

    sqljdbc_4.2.8112.200_chs.rar

    此外,它还包含了官方的sample,这些示例代码可以帮助开发者更好地理解和使用SQL Server JDBC驱动,快速上手数据库操作。 SQL Server JDBC驱动的核心功能包括: 1. 数据源连接:驱动提供了DataSource接口,允许...

    springBoot和sharding-jdbc、mybatis整合demo

    MyBatis避免了几乎所有的JDBC代码和手动设置参数以及获取结果集。它使开发者能够专注于SQL本身,而无需关注那些臃肿和容易出错的JDBC代码。 在本示例项目中,我们看到"resources/sql"目录下包含了针对不同数据库的...

Global site tag (gtag.js) - Google Analytics