SELECT语句使用JDBC和Hibernate批量获取

介绍

现在,我已经介绍了HibernateINSERTUPDATEDELETE语句的批处理支持,是时候分析SELECT语句结果集的批量提取了。

JDBC ResultSet提供了一个客户端代理游标,用于获取当前语句的返回数据。 执行该语句后,必须将结果从数据库游标传输到客户端。 此操作可以立即执行,也可以根据需要执行。

ResultSet游标有三种类型 :

游标类型 描述
TYPE_FORWARD_ONLY 这是默认的ResultSet游标类型。 结果集只能向前移动,并且结果数据可以一次获取,也可以在迭代游标时检索。 数据库可以决定在查询开始时还是在获取时获取可用的数据。
TYPE_SCROLL_INSENSITIVE 可以向前和向后滚动结果集,并且结果数据对游标仍处于打开状态时发生的并发更改不敏感
TYPE_SCROLL_SENSITIVE 可以向前和向后滚动结果集,并且结果数据在游标仍处于打开状态时发生的并发更改敏感 。 因此,数据是按需获取的,而不是从数据库游标缓存中获取的


并非所有数据库驱动程序都实现所有游标类型,并且批处理获取行为是通过JDBC语句 fetchSize属性控制的,根据Javadoc

当此Statement生成的ResultSet对象需要更多行时,向JDBC驱动程序提供有关应该从数据库中获取的行数的提示。 如果指定的值为零,则忽略提示。 默认值为零。

因此,默认的获取策略是特定于数据库的,从应用程序性能的角度来看,这方面在调整数据访问层时非常重要:

  • 甲骨文

    默认情况下, Oracle JDBC运行查询时,它一次从数据库游标中检索10行的结果集。根据Oracle JDBC驱动程序文档 :“合理的”取决于应用程序的详细信息。 Oracle建议fetchSize不超过100,尽管在某些情况下可能更合适。 对于某些查询,即使返回许多行, fetchSize可能也会过大。
  • 的MySQL

    默认情况下, 结果集是完全检索和存储在内存中。 在大多数情况下,这是最有效的操作方式,并且由于MySQL网络协议的设计,因此更易于实现。
  • SQL服务器

    通常,当用于SQL ServerMicrosoft JDBC驱动程序执行查询时,驱动程序会将所有结果从服务器检索到应用程序内存中。 尽管这种方法最大程度地减少了SQL Server上的资源消耗,但它可以在JDBC应用程序中引发产生非常大结果的查询的OutOfMemoryError
  • PostgreSQL的

    默认情况下,驱动程序会立即收集查询的所有结果。 这对于大型数据集可能很不方便,因此JDBC驱动程序提供了一种将ResultSet基于数据库游标并且仅获取少量行的方法。
  • DB2

    默认情况下,驱动程序会立即收集查询的所有结果。 这对于大型数据集可能很不方便,因此JDBC驱动程序提供了一种将ResultSet基于数据库游标并且仅获取少量行的方法。 fetchSize属性与queryDataSize属性不同。 fetchSize影响返回的行数,而queryDataSize影响返回的字节数。

    例如,如果结果集大小为50 KB,而queryDataSize的值为32767(32KB),则需要两次到数据库服务器的行程才能检索结果集。 但是,如果将queryDataSize设置为65535(64 KB),则只需一趟数据源即可检索结果集。

Java Persistence Query接口通过Query.getResultList()方法调用仅提供全结果检索。

Hibernate还通过其特定的Query.scroll() API支持可滚动的ResultSet游标。

可滚动的ResultSets唯一明显的优点是,由于可以按需获取数据,因此我们可以避免客户端的内存问题。 这听起来似乎是很自然的选择,但实际上,由于以下原因,您不应该获取大型结果集:

  • 结果集较大会占用大量数据库服务器资源,并且由于数据库是高度并发的环境 ,因此可能会妨碍可用性和可伸缩性
  • 表的大小趋于增长,适度的结果集可能很容易变成很大的表。 这种情况发生在生产系统中,很早就发布了应用程序代码。 由于用户只能浏览整个结果集中的一小部分,因此分页是一种更具可伸缩性的数据提取方法
  • 过于常见的偏移分页不适用于大型结果集(因为响应时间随页码线性增加),并且在遍历大型结果集时应考虑键集分页 。 键集分页提供了恒定的响应时间 ,对正在获取的页面的相对位置不敏感
  • 即使对于批处理作业 ,将处理项目限制为适当的批处理大小总是比较安全的。 大批量可能导致内存问题或导致长时间运行的事务,从而增加了撤消/重做事务日志的大小

测试时间

我们的域实体模型如下所示:

postcommentfetchsize

以下测试将用于验证各种结果集的获取行为:

@Test
public void testFetchSize() {doInTransaction(session -> {int batchSize = batchSize();for(int i = 0; i < itemsCount(); i++) {Post post = new Post(String.format("Post no. %d", i));int j = 0;post.addComment(new Comment(String.format("Post comment %d:%d", i, j++)));post.addComment(new Comment(String.format("Post comment %d:%d", i, j++)));session.persist(post);if(i % batchSize == 0 && i > 0) {session.flush();session.clear();}}});long startNanos = System.nanoTime();LOGGER.info("Test fetch size");doInTransaction(session -> {List posts = session.createQuery("select p " +"from Post p " +"join fetch p.comments ").list();LOGGER.info("{}.fetched {} entities",getClass().getSimpleName(),posts.size());});LOGGER.info("{}.testFetch took {} millis",getClass().getSimpleName(),TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - startNanos));
}

要将Hibernate配置为使用显式Statement fetchSize ,我们需要设置以下Hibernate属性:

properties.put("hibernate.jdbc.fetch_size", fetchSize());

每个测试将插入5000个Post实体,每个实体具有2个Comment

针对商业数据库运行第一个测试,结果如下:

提取大小 持续时间[毫秒]
1个 1190
10 640
100 481
1000 459
10000 449
默认值(10) 545


提取大小越大,则提取整个结果集所需的往返行程越少。 如果返回的行包含许多列,则较大的访存大小将按比例需要较大的数据库缓冲区。

第二轮测试针对PostgreSQL 9.4运行,结果如下:

提取大小 持续时间[毫秒]
1个 1181
10 572
100 485
1000 458
10000 437
默认(全部) 396


即使fetchSize等于要返回的总行数,默认的fetch大小也会产生最佳结果。 由于没有上限缓冲区限制,因此在检索大型结果集时,默认的提取大小可能会导致OutOfMemoryError问题。

结论

虽然大多数数据库服务都不会对结果集的获取大小施加默认上限,但是最好限制整个结果集(如果要求允许的话)。 大小有限的结果集应解决无限制的获取大小缺陷,同时即使在查询的数据逐渐增长的情况下,也要确保可预测的响应时间。 查询越短,行级锁被释放的越快,数据访问层的可伸缩性就越高 。

  • 代码可在GitHub上获得 。

翻译自: https://www.javacodegeeks.com/2015/04/select-statements-batch-fetching-with-jdbc-and-hibernate.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/360109.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

linux 更改父进程名称,[Linux进程]在父进程和子进程中分别修改变量

/*这是一个调用fork函数创建一个子进程&#xff0c;然后分别打印输出子进程和父进程中的变量的实例*/#include #include #include #include int glob 6; //外部变量int main(void){int var; //内部变量pid_t pid; //文件标识符var 88;//内部变量printf("…

Spring环境的搭建与测试 (spring2.5.6)

这里是采用的视频里面的spring版本 下载spring2.5.6&#xff0c; 然后进行解压缩&#xff0c;在解压目录中找到下面jar文件&#xff0c;拷贝到类路径下 dist\spring.jar lib\jakarta-commons\commons-logging.jar 上边两个是基本的jar包。。 如果使用了切面编程(AOP),还需要下列…

linux 多核 系统时钟,Linux中的时间

1. Linux中time相关概念1.1 real time指的是实际流逝的时间&#xff0c;又称为Wall Clock Time(墙上时间)。比如&#xff0c;time命令统计出的real time指的是该进程从开始运行到运行结束所消耗的时间。在这段时间内不仅仅执行了该进程&#xff0c;其他进程的时间片也得到了轮转…

经纬度 在线计算距离

http://www.storyday.com/wp-content/uploads/2008/09/latlung_dis.html 转载于:https://www.cnblogs.com/sgdkg/p/3558112.html

如何使用Hibernate批处理INSERT和UPDATE语句

介绍 JDBC长期以来一直为DML语句批处理提供支持。 默认情况下&#xff0c;所有语句都一个接一个地发送&#xff0c;每个语句都在单独的网络往返中发送。 批处理使我们能够一次性发送多个语句&#xff0c;从而节省了不必要的套接字流刷新。 Hibernate将数据库语句隐藏在事务后写…

【ASP.NET Web API教程】5.4 ASP.NET Web API批处理器

【ASP.NET Web API教程】5.4 ASP.NET Web API批处理器 原文:【ASP.NET Web API教程】5.4 ASP.NET Web API批处理器注&#xff1a;本文是【ASP.NET Web API系列教程】的一部分&#xff0c;如果您是第一次看本系列教程&#xff0c;请先看前面的内容。 Batching Handler for ASP.N…

linux 查看系统组账号密码是什么,Linux 用户与组管理详解(system-config-users 命令行)...

用户与组管理用户相关文件组账号相关文件用户和组管理软件&#xff1a;基于命令行的用户和组管理创建用户查看用户信息删除用户修改用户信息为用户创建密码更改用户密码信息创建组删除组查看当前登录到系统的用户用户与组管理什么是用户&#xff0c;用户是人吗&#xff1f;用户…

C++中指针和引用的选择

何时使用引用和指针1. 尽可能使用引用传递参数2. 尽可能的使用const来保护引用和指针3. 在可以使用引用的时候不要使用指针4. 不要试图给引用重新赋值&#xff0c;使之指向另一个变量&#xff0c;这是不可能的&#xff08;因为引用是变量的别名&#xff0c;和变量是统一的&…

linux 7 没有权限访问,[CentOS 7系列]文件或目录的权限与属性

在开始今天的话题之前&#xff0c;我们首先来回顾下ls命令。在ls命令中参数“-l”会显示出来目标的详细信息&#xff0c;如下所示&#xff1a;[rootserver02~]#ls-l/tmp/总用量4-rwx------.1rootroot8365月2706:19ks-script-ogzDFAdrwxr-xr-x.5rootroot755月3005:26testdrwxr-x…

POJ 2386 Lake Counting DFS水水

http://poj.org/problem?id2386 题目大意&#xff1a; 有一个大小为N*M的园子&#xff0c;雨后积起了水。八连通的积水被认为是连接在一起的。请求出院子里共有多少水洼&#xff1f; 思路&#xff1a; 水题~直接DFS&#xff0c;DFS过程把途中表示水洼的W改为‘.&#xff0c;看…

linux没有root密码xshell,LINUX终端免密登陆(以Xshell为例)

1&#xff0c;工具-新建用户密钥生成向导linux2&#xff0c;密钥类型选择&#xff1a;RSA&#xff0c;而后下一步shell3&#xff0c;输入密钥名称和密码ssh4&#xff0c;公钥格式为SSH-OpenSSH,保存为文件(后缀为pub)(记录此文件目录)工具二&#xff0c;登陆在须要免密登陆的主…

ActionBar之style出现Cannot resolve symbol 'Theme' 错误

今天 2014/03/08 00:49 刚刚升级 android studio 到了 0.5.0 版本&#xff0c;修复了许多 bug&#xff0c;包含当前这个问题&#xff0c;之前一直困扰我很久&#xff0c;莫名奇妙的提示主题样式找不到&#xff0c;无法解析&#xff0c; 后来一直谷歌发现很多人都认为是 IDE 的b…

单片机上运行linux程序代码,在Linux下烧录51单片机

原标题&#xff1a;在Linux下烧录51单片机*本文作者&#xff1a;LEdge1&#xff0c;本文属 FreeBuf原创奖励计划&#xff0c;未经许可禁止转载。背景我一直在学习Linux 系统&#xff0c;但是最近还要学习51单片机&#xff0c;所以在Linux下给51单片机烧录程序那是非常必要的。之…

linux运行core控制台程序,VisualStudioCode创建的asp.net core控制台程序部署到linux

1、asp.net core控制台程序static void Main(string[] args){int times10;while(times>0){Console.WriteLine("Hello World!");times--;Thread.Sleep(1000);}}2、发布发布前&#xff0c;修改test2.csproj文件(项目名称为test2)Exenetcoreapp2.1centos.7-x64主要添…

StringTokenizer(字符串分隔解析类型)

java.util.StringTokenizer 功效:将字符串以定界符为界&#xff0c;分析为一个个的token&#xff08;可理解为单词&#xff09;&#xff0c;定界符可以自己指定。 &#xff11;、构造函数。1. StringTokenizer(String str) &#xff1a;构造一个用来解析str的StringTokenizer对…

linux 秒数转时间格式,通过delphi将秒数转换成日期格式

摘要将秒数转换成日期格式&#xff0c;是经常用到的一个算法&#xff0c;下面有几个方法&#xff0c;可以借鉴具体代码1&#xff1a;转换成HH:MM:SS格式的字符串格式&#xff1a;function SecondToTime(a:integer):string;beginresult:timetostr(a/86400);end;或者function Sec…

Watch online

1.youku 在优酷看视视频时可登录m.youku.com/wap,在IE上都不需wap,但在chrome上不加会自动跳转成www.youku.com。那上面的视频是一个整体&#xff0c;可以用迅雷下也可在浏览器上直接看。 随便搜了下&#xff0c;发现可直接利用www.youku.com上的视频ID找到上述可直接播放下载的…

java开机自启动 Linux,java项目jar包开机自启(WINDOWS,Linux)

WINDOWS:1.新建一个text文件&#xff0c;将 java -jar D:\eclipse-workspace\attendance\target\mybatis-generator.jar写入&#xff0c;修改文件为.bat文件。2.编写run.vbs文件&#xff0c;新建一个run.text文件&#xff0c;将下面代码写入,然后将文件后缀改为.vbsSet ws Cre…

PHP中,json汉字编码

当用json与js或者其它客户端交互时&#xff0c;如果有中文&#xff0c;则会变成unicode。虽然能使用&#xff0c;但是影响观看。不好调试呀。从网上找到了几个方法 一&#xff0c;用下面这个函数&#xff0c;需要编码时&#xff0c;直接调用这个函数就成 function jsonEnco…

[收藏] Opera鼠标手势命令

Opera的Presto内核版本已经不复存在了&#xff01;&#xff01;惋惜&#xff01;痛惜&#xff01; 现在我的电脑硬盘里还保存着两个版本&#xff0c;一个是第三方优化版的v11.00 1156&#xff0c;另一个是Presto的最终官方版&#xff1a;v12.16&#xff0c;现在看起来都有一种莫…