JDBC中Fetchsize的實(shí)現(xiàn)
1. 什么是fetchsize?
1.1 Oracle中的fetchsize
當(dāng)我們執(zhí)行一個(gè)SQL查詢語句的時(shí)候,需要在客戶端和服務(wù)器端都打開一個(gè)游標(biāo),并且分別申請一塊內(nèi)存空間,作為存放查詢的數(shù)據(jù)的一個(gè)緩沖區(qū)。這塊內(nèi)存區(qū),存放多少條數(shù)據(jù)就由fetchsize來決定,同時(shí)每次網(wǎng)絡(luò)包會(huì)傳送fetchsize條記錄到客戶端。應(yīng)該很容易理解,如果fetchsize設(shè)置為20,當(dāng)我們從服務(wù)器端查詢數(shù)據(jù)往客戶端傳送時(shí),每次可以傳送20條數(shù)據(jù),但是兩端分別需要20條數(shù)據(jù)的內(nèi)存空閑來保存這些數(shù)據(jù)。fetchsize決定了每批次可以傳輸?shù)挠涗洍l數(shù),但同時(shí),也決定了內(nèi)存的大小。這塊內(nèi)存,在oracle服務(wù)器端是動(dòng)態(tài)分配的(大家可以想想為什么)。而在客戶端(JBOSS),PS對(duì)象會(huì)存在一個(gè)緩沖中(LRU鏈表),也就是說,這塊內(nèi)存是事先配好的,應(yīng)用端內(nèi)存的分配在conn.prepareStatement(sql)或conn.CreateStatement(sql)的時(shí)候完成。
例如:
//打開游標(biāo),執(zhí)行查詢,但是并不獲取任何的數(shù)據(jù),網(wǎng)絡(luò)上沒有數(shù)據(jù)的傳輸。 rs = stmt.executeQuery(); //獲取具體的數(shù)據(jù),網(wǎng)絡(luò)一般每次傳輸fetchsize條數(shù)據(jù)。 while (rs.next()){ }
1.2 Mysql中的fetchsize
Mysql的preparestament基本上不占用內(nèi)存,為什么呢?因?yàn)镸ysql并不需要象Oracle那樣的一塊內(nèi)存來保存結(jié)果集緩沖區(qū),為什么不需要緩沖區(qū),其中根本的原因是由Mysql的通訊方式?jīng)Q定的。Mysql客戶端/服務(wù)器協(xié)議是半雙工的,即Mysql只能在給定的時(shí)間,發(fā)送或接受數(shù)據(jù),但不能同時(shí)發(fā)送和接收。所以,Mysql在數(shù)據(jù)查詢結(jié)果集傳送的時(shí)候,需要一次性將數(shù)據(jù)全部傳送到客戶端,在客戶數(shù)據(jù)接收完之后,釋放相關(guān)的鎖等資源。因?yàn)檫@種半雙工的通訊方式,所以Mysql不需要客戶端的游標(biāo),但是客戶端API通過把結(jié)果取到內(nèi)存中,可以模擬游標(biāo)的操作。所以,我們可以在JAVA程序中,可以象Oracle那樣來實(shí)現(xiàn)Mysql的訪問。
注意:
useCursorFetch=true 是針對(duì) MySQL 數(shù)據(jù)庫的 JDBC 連接參數(shù),用于啟用服務(wù)器端游標(biāo)獲取數(shù)據(jù)。在 MyBatis 中,當(dāng)使用流式查詢(例如:分頁查詢、結(jié)果集處理和使用游標(biāo)等)時(shí),這個(gè)配置可以幫助逐行從服務(wù)器檢索數(shù)據(jù),而不是一次性將所有數(shù)據(jù)加載到內(nèi)存中,從而降低內(nèi)存占用。
當(dāng)使用 MySQL 數(shù)據(jù)庫時(shí),在 JDBC 連接字符串中加入 useCursorFetch=true,并結(jié)合設(shè)置合適的 fetchSize,可以避免因一次性加載過多數(shù)據(jù)導(dǎo)致的內(nèi)存溢出問題。注意,此配置僅對(duì) MySQL 數(shù)據(jù)庫有效。 如果不設(shè)置 useCursorFetch=true 這個(gè)配置,僅使用之前提到的那些配置(如設(shè)置 defaultFetchSize、分頁查詢、結(jié)果集處理和使用游標(biāo)等),在大多數(shù)情況下,這些配置仍然可以有效地避免查詢導(dǎo)致的內(nèi)存溢出。
但需要注意的是,對(duì)于 MySQL 數(shù)據(jù)庫,如果不啟用服務(wù)器端游標(biāo)獲取數(shù)據(jù),這可能會(huì)影響到流式查詢的效果。因?yàn)樵谀J(rèn)情況下,MySQL JDBC 驅(qū)動(dòng)會(huì)一次性將所有數(shù)據(jù)加載到內(nèi)存中。此時(shí),即使使用了其他配置,也可能無法達(dá)到預(yù)期的內(nèi)存優(yōu)化效果。
總的來說,在使用 MySQL 數(shù)據(jù)庫時(shí),推薦在 JDBC 連接字符串中加入 useCursorFetch=true 配置,以更好地支持流式查詢和降低內(nèi)存占用。在其他數(shù)據(jù)庫中,可以根據(jù)實(shí)際需求和場景選擇合適的配置和策略來避免查詢導(dǎo)致的內(nèi)存溢出。
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的默認(rèn)值
在ojdbc8的源碼中oracle的驅(qū)動(dòng)的fetchsize參數(shù)的默認(rèn)值是10
2.3 fetchsize的設(shè)置
2.3.1 Mybatis全局設(shè)置
通過設(shè)置 MyBatis 配置文件中的 defaultFetchSize 值:
<settings> <setting name="defaultFetchSize" value="合適的值" /> </settings>
2.3.2 語句級(jí)別的設(shè)置
可以在jdbc中調(diào)用Preparedstatement .setFetchSize()的進(jìn)行設(shè)置:
stmt = conn.prepareStatement(sql); stmt.setFetchSize(50);
2.3.3 框架上直接針對(duì)某個(gè)語句進(jìn)行設(shè)置
可以在Mybatis的查詢語句上進(jìn)行設(shè)置:
<select id="selectFetchSize" fetchSize="100" resultSetType="FORWARD_ONLY" resultType="com.example.poi.entity.EntityDemo"> select * from entity_demo </select>
Mybatis中的定義:
fetchSize:fetchSize屬性用于指定每次從數(shù)據(jù)庫獲取的記錄數(shù)。這個(gè)屬性可以用于控制查詢操作的內(nèi)存使用和性能。
當(dāng)設(shè)置fetchSize時(shí),MyBatis會(huì)根據(jù)這個(gè)值來調(diào)整JDBC的Statement對(duì)象的fetchSize屬性。如果數(shù)據(jù)庫和JDBC驅(qū)動(dòng)支持,這可以減少網(wǎng)絡(luò)往返次數(shù),提高性能。
在分頁查詢或處理大量數(shù)據(jù)時(shí),合理設(shè)置fetchSize可以有效地控制每次從數(shù)據(jù)庫拉取的數(shù)據(jù)量,防止內(nèi)存溢出。
在您的例子中,fetchSize="100"意味著每次從數(shù)據(jù)庫獲取100條記錄。
resultSetType:
resultSetType屬性用于定義結(jié)果集的滾動(dòng)方向。MyBatis支持以下幾種類型:
FORWARD_ONLY:結(jié)果集只能向前滾動(dòng),這是默認(rèn)值,適用于大多數(shù)情況。
SCROLL_SENSITIVE:結(jié)果集可以向前或向后滾動(dòng),并且可以檢測到數(shù)據(jù)庫中的數(shù)據(jù)變化。
SCROLL_INSENSITIVE:結(jié)果集可以向前或向后滾動(dòng),但不會(huì)檢測到數(shù)據(jù)庫中的數(shù)據(jù)變化。
這個(gè)屬性影響JDBC的Statement對(duì)象的resultSetType,它決定了結(jié)果集的可滾動(dòng)性和可更新性。
在您的例子中,resultSetType="FORWARD_ONLY"意味著結(jié)果集只能向前滾動(dòng),這是最常用的類型,因?yàn)樗ǔL峁└玫男阅堋?br />使用fetchSize和resultSetType可以幫助優(yōu)化查詢性能和資源使用。在處理大量數(shù)據(jù)或需要特定結(jié)果集行為時(shí),這些屬性尤其有用。然而,它們的實(shí)際效果還取決于數(shù)據(jù)庫驅(qū)動(dòng)程序和數(shù)據(jù)庫服務(wù)器的性能特性。
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);
到此這篇關(guān)于JDBC中Fetchsize的實(shí)現(xiàn)的文章就介紹到這了,更多相關(guān)JDBC Fetchsize內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- SpringBoot+MybatisPlus實(shí)現(xiàn)sharding-jdbc分庫分表的示例代碼
- JDBC如何連接mysql
- sharding-jdbc實(shí)現(xiàn)分頁查詢的示例代碼
- 解決mybatis plus報(bào)錯(cuò)com.microsoft.sqlserver.jdbc.SQLServerException:必須執(zhí)行該語句才能獲得結(jié)果
- ShardingSphere JDBC強(qiáng)制路由使用的項(xiàng)目實(shí)踐
- springboot jdbctemplate如何實(shí)現(xiàn)多數(shù)據(jù)源
- sharding-jdbc 兼容 MybatisPlus動(dòng)態(tài)數(shù)據(jù)源的配置方法

springboot log4j2不能打印框架錯(cuò)誤日志的解決方案

java經(jīng)典問題:連個(gè)字符串互為回環(huán)變位

一文帶你看懂Android動(dòng)畫的實(shí)現(xiàn)原理

Java的面向?qū)ο缶幊袒靖拍顚W(xué)習(xí)筆記整理

SpringCloud全局過慮器GlobalFilter的用法小結(jié)

關(guān)于Scanner中nextInt()、nextLine()等方法總結(jié)與問題解決