java

关注公众号 jb51net

关闭
首页 > 软件编程 > java > JDBC Fetchsize

JDBC中Fetchsize的实现

作者: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内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

您可能感兴趣的文章:
阅读全文