日期:2014-05-16 浏览次数:20580 次
当我们为了完成某个业务逻辑,需要从数据库系统返回记录过多的结果集的时候,往往会引发多方面的问题,这些问题包括:性能优化设计策略、结果集的分页技术等等。对于开发人员来说,都是无法避免的。
先看看数据库查询大结果集可能带来的问题:
(1),内存占有过大。如果我们一次性把成千上万条记录保存在内存的话,内存势必会消耗过大,这使得JVM虚拟机能运用的内存空间减少,数据交换的速度减低,导致服务性能明显降低;而且,很容易引发内存不足不可恢复异常,最后导致整个服务瘫痪。
(2),网络传输阻塞。一般情况下,数据库服务都是独立一台机器,如果我们一次性从数据库返回大量数据的话,很容易瞬间导致网络阻塞,特别是当用户并发访问很大的时时候,情况更加明显。
(3),数据显示问题。如果一次性把成千上万条记录用一个页面或窗口呈献给查询用户,容易造成客户视觉疲劳,所以我们要考虑分页显示。
针对不同的问题,我们解决问题的方法也不尽相同。对待大结果集数据分页的处理上,我们一般的设计策略有以下3种方式:
(一),把结果集所有的数据一次性查询出来,放在应用服务器内存中,然后再分页处理。
这是一种很常见的思路,它的优点是:解藕了ResultSet操作类和数据库查询游标的关系,使得数据库连接得到有效的释放,提高了数据库并发访问的性能。同时,把数据导在本地,处理十分简单。由于数据都在内存中,翻页查询没有必要再从数据库请求数据,直接从内存获取就可以了,因而,响应更快。其缺点有:由于数据缓存在内存中,客户查询有可能看到的是过期数据;如果查询结果集数据量非常大的话,第一次查询遍历结果集会很耗时间,而且缓存这样大的数据也会造成内存消耗过大,使得JVM的效率明显降低。所以,这种方式对于查询结果在1000条以内的“小”结果集,而且数据完整性要求不高的情况下,可以采用,而且也十分简单有效。
(二),对查询结果集进行业务分析,针对查询客户的需要,把客户最为关心的数据首先呈献给客户,对于一些老数据,放入历史库,另外提供一个历史查询模块给客户使用。
这其实是把查询结果集按照客户的需要拆分开,避免了问题的主要矛盾,当然,前提是假设了用户实时关心的数据并不多。例如,对新闻数据查询,客户可能最关心的就是近3天的新闻信息,其它过期新闻可能1个月也不会查询一次。这个方式主要基于业务上设计策略,实现的技术也是甚为灵活。
(三),查询结果集所有的数据仍然留在数据库服务器端。每次翻页,我们都根据页面大小只从数据库服务器里面检索并返回块区数据,直到检索完所有的记录。
由于每次查询的记录数很少,网络传输数据量不大,不会造成阻塞。而且,数据都是由数据库统一提供,不会存在数据过期问题。应该说,这种方式是解决数据分页的理想方式。
实现方式(三)的技术常见有:
■直接使用JDBC底层的ResultSet接口,利用游标来处理。
ResultSet本质是在数据库服务器上建立游标,然后通过行位置定位数据记录。这种方法,当客户第一请求数据时,就执行查询语句,获得ResultSet对象,保存在会话中,以后分页获取数据时都是通过ResultSet对象来定位和获取指定位置的记录。最后,当客户不再进行分页查询的时候,就关闭会话,释放数据库连接和ResultSet等等数据访问资源。
优点:减少sql语句查询的次数,利用标准API实现,便于系统移植。