JDBC中Fetchsize的实现

 更新时间:2024年09月27日 10:31:21   作者:Desiro_  
fetchsize是指在执行数据库查询时,每次从数据库中获取的记录条数,它对内存使用和网络传输效率有重要影响,在MyBatis中,可以通过全局设置或语句级别设置fetchsize,来控制查询操作的内存使用和提升性能,合理的fetchsize设置能有效减少网络往返次数和防止内存溢出

1. 什么是fetchsize?

1.1  Oracle中的fetchsize

当我们执行一个SQL查询语句的时候,需要在客户端和服务器端都打开一个游标,并且分别申请一块内存空间,作为存放查询的数据的一个缓冲区。这块内存区,存放多少条数据就由fetchsize来决定,同时每次网络包会传送fetchsize条记录到客户端。应该很容易理解,如果fetchsize设置为20,当我们从服务器端查询数据往客户端传送时,每次可以传送20条数据,但是两端分别需要20条数据的内存空闲来保存这些数据。fetchsize决定了每批次可以传输的记录条数,但同时,也决定了内存的大小。这块内存,在oracle服务器端是动态分配的(大家可以想想为什么)。而在客户端(JBOSS),PS对象会存在一个缓冲中(LRU链表),也就是说,这块内存是事先配好的,应用端内存的分配在conn.prepareStatement(sql)或conn.CreateStatement(sql)的时候完成。

例如:

//打开游标,执行查询,但是并不获取任何的数据,网络上没有数据的传输。
rs = stmt.executeQuery();
//获取具体的数据,网络一般每次传输fetchsize条数据。
while (rs.next()){
}

1.2  Mysql中的fetchsize

Mysql的preparestament基本上不占用内存,为什么呢?因为Mysql并不需要象Oracle那样的一块内存来保存结果集缓冲区,为什么不需要缓冲区,其中根本的原因是由Mysql的通讯方式决定的。Mysql客户端/服务器协议是半双工的,即Mysql只能在给定的时间,发送或接受数据,但不能同时发送和接收。所以,Mysql在数据查询结果集传送的时候,需要一次性将数据全部传送到客户端,在客户数据接收完之后,释放相关的锁等资源。因为这种半双工的通讯方式,所以Mysql不需要客户端的游标,但是客户端API通过把结果取到内存中,可以模拟游标的操作。所以,我们可以在JAVA程序中,可以象Oracle那样来实现Mysql的访问。

注意:

useCursorFetch=true 是针对 MySQL 数据库的 JDBC 连接参数,用于启用服务器端游标获取数据。在 MyBatis 中,当使用流式查询(例如:分页查询、结果集处理和使用游标等)时,这个配置可以帮助逐行从服务器检索数据,而不是一次性将所有数据加载到内存中,从而降低内存占用。

当使用 MySQL 数据库时,在 JDBC 连接字符串中加入 useCursorFetch=true,并结合设置合适的 fetchSize,可以避免因一次性加载过多数据导致的内存溢出问题。注意,此配置仅对 MySQL 数据库有效。 如果不设置 useCursorFetch=true 这个配置,仅使用之前提到的那些配置(如设置 defaultFetchSize、分页查询、结果集处理和使用游标等),在大多数情况下,这些配置仍然可以有效地避免查询导致的内存溢出。

但需要注意的是,对于 MySQL 数据库,如果不启用服务器端游标获取数据,这可能会影响到流式查询的效果。因为在默认情况下,MySQL JDBC 驱动会一次性将所有数据加载到内存中。此时,即使使用了其他配置,也可能无法达到预期的内存优化效果。

总的来说,在使用 MySQL 数据库时,推荐在 JDBC 连接字符串中加入 useCursorFetch=true 配置,以更好地支持流式查询和降低内存占用。在其他数据库中,可以根据实际需求和场景选择合适的配置和策略来避免查询导致的内存溢出。

2. 使用fetchsize

2.1 fetchsize的作用

Java doc

Gives the JDBC driver a hint as to the number of rows that should be fetched from the database when more rows are needed for this ResultSet object. If the fetch size specified is zero, the JDBC driver ignores the value and is free to make its own best guess as to what the fetch size should be. The default value is set by the Statement object that created the result set. The fetch size may be changed at any time.

2.2 fetchsize的默认值

在ojdbc8的源码中oracle的驱动的fetchsize参数的默认值是10

2.3 fetchsize的设置

2.3.1 Mybatis全局设置

通过设置 MyBatis 配置文件中的 defaultFetchSize 值:

<settings>
    <setting name="defaultFetchSize" value="合适的值" />
</settings>

2.3.2 语句级别的设置

可以在jdbc中调用Preparedstatement .setFetchSize()的进行设置:

stmt = conn.prepareStatement(sql);
stmt.setFetchSize(50);

2.3.3 框架上直接针对某个语句进行设置

可以在Mybatis的查询语句上进行设置:

<select id="selectFetchSize" fetchSize="100" resultSetType="FORWARD_ONLY" resultType="com.example.poi.entity.EntityDemo">
    select * from entity_demo
</select>

Mybatis中的定义: 

fetchSize:fetchSize属性用于指定每次从数据库获取的记录数。这个属性可以用于控制查询操作的内存使用和性能。
当设置fetchSize时,MyBatis会根据这个值来调整JDBC的Statement对象的fetchSize属性。如果数据库和JDBC驱动支持,这可以减少网络往返次数,提高性能。
在分页查询或处理大量数据时,合理设置fetchSize可以有效地控制每次从数据库拉取的数据量,防止内存溢出。
在您的例子中,fetchSize="100"意味着每次从数据库获取100条记录。
resultSetType:
resultSetType属性用于定义结果集的滚动方向。MyBatis支持以下几种类型:
FORWARD_ONLY:结果集只能向前滚动,这是默认值,适用于大多数情况。
SCROLL_SENSITIVE:结果集可以向前或向后滚动,并且可以检测到数据库中的数据变化。
SCROLL_INSENSITIVE:结果集可以向前或向后滚动,但不会检测到数据库中的数据变化。
这个属性影响JDBC的Statement对象的resultSetType,它决定了结果集的可滚动性和可更新性。
在您的例子中,resultSetType="FORWARD_ONLY"意味着结果集只能向前滚动,这是最常用的类型,因为它通常提供更好的性能。
使用fetchSize和resultSetType可以帮助优化查询性能和资源使用。在处理大量数据或需要特定结果集行为时,这些属性尤其有用。然而,它们的实际效果还取决于数据库驱动程序和数据库服务器的性能特性。

2.3.4 使用注解

在Mybatis3.2中可以使用注解:

@Select("select * from entity_demo t ${ew.customSqlSegment}")
@Options(resultSetType = ResultSetType.FORWARD_ONLY, fetchSize = 100)
@ResultType(Entity_demo.class)
void selectFetchSize(@Param(Constants.WRAPPER) QueryWrapper<Entity_demo> wrapper,ResultHandler<entity_demo> handler);

到此这篇关于JDBC中Fetchsize的实现的文章就介绍到这了,更多相关JDBC Fetchsize内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • Spring Boot整合Kafka教程详解

    Spring Boot整合Kafka教程详解

    这篇文章主要为大家介绍了Spring Boot整合Kafka教程详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-03-03
  • 详解Java线程池队列中的延迟队列DelayQueue

    详解Java线程池队列中的延迟队列DelayQueue

    这篇文章主要为大家详细介绍了Java线程池队列中的延迟队列DelayQueue的相关资料,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下
    2022-12-12
  • Java设计模式中装饰者模式应用详解

    Java设计模式中装饰者模式应用详解

    装饰者模式:在不改变原有对象的基础之上,动态的将功能附加到对象上,提供了继承更有弹性的替代方案,也体现了开闭原则。本文将通过示例详细讲解一下装饰者模式,需要的可以参考一下
    2022-11-11
  • 解决Eclipse中java文件的图标变成空心J的问题

    解决Eclipse中java文件的图标变成空心J的问题

    这篇文章主要介绍了解决Eclipse中java文件的图标变成空心J的问题,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2021-01-01
  • ActiveMQ基于zookeeper的主从(levelDB Master/Slave)搭建

    ActiveMQ基于zookeeper的主从(levelDB Master/Slave)搭建

    这篇文章主要介绍了ActiveMQ基于zookeeper的主从levelDB Master/Slave搭建,以及Spring-boot下的使用方法,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2017-08-08
  • JavaWeb工程中集成YMP框架快速上手

    JavaWeb工程中集成YMP框架快速上手

    YMP是一个非常简单、易用的一套轻量级JAVA应用开发框架,设计原则主要侧重于简化工作任务、规范开发流程、提高开发效率。对YMP框架感兴趣的小伙伴们可以参考一下
    2016-02-02
  • Java用三元运算符判断奇数和偶数的简单实现

    Java用三元运算符判断奇数和偶数的简单实现

    这篇文章主要介绍了Java用三元运算符判断奇数和偶数的简单实现,需要的朋友可以参考下
    2014-02-02
  • 简单学习Java+MongoDB

    简单学习Java+MongoDB

    本文给大家介绍的是如何简单的使用java+MongoDB实现数据调用的问题,非常的实用,有需要的小伙伴可以参考下
    2016-03-03
  • Java下载项目中静态文件方式

    Java下载项目中静态文件方式

    这篇文章主要介绍了Java下载项目中静态文件方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2023-08-08
  • Mybatis自定义插件Interceptor问题

    Mybatis自定义插件Interceptor问题

    这篇文章主要介绍了Mybatis自定义插件Interceptor问题,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-11-11

最新评论