3 回答

TA貢獻(xiàn)1796條經(jīng)驗(yàn) 獲得超7個(gè)贊
您應(yīng)該在幾個(gè)級(jí)別上處理此問(wèn)題:
JDBC驅(qū)動(dòng)程序訪存大小
JDBC有一個(gè)Statement.setFetchSize()方法,該方法指示從JDBC獲取行之前,JDBC驅(qū)動(dòng)程序?qū)㈩A(yù)取多少行。請(qǐng)注意,MySQL JDBC驅(qū)動(dòng)程序并未真正正確地實(shí)現(xiàn)此功能,但您可以設(shè)置setFetchSize(Integer.MIN_VALUE)為阻止它一次性獲取所有行。另請(qǐng)參閱此答案。
請(qǐng)注意,您還可以使用以下方法激活連接上的功能 useCursorFetch
你自己的邏輯
您不應(yīng)將整個(gè)用戶(hù)列表存儲(chǔ)在內(nèi)存中。您現(xiàn)在正在做的是從JDBC收集所有行,然后稍后使用來(lái)對(duì)列表進(jìn)行分區(qū)Lists.partition(users, 2000)。這是朝著正確的方向發(fā)展,但是您做的還不是很正確。相反,請(qǐng)執(zhí)行以下操作:
try (ResultSet rs = cs.executeQuery()) {
while (rs.next()) {
res.add(new ImmutablePair<>(rs.getLong(1), rs.getString(2)));
}
// Process a batch of rows:
if (res.size() >= 2000) {
process(res);
res.clear();
}
}
// Process the remaining rows
process(res);
此處的重要信息是不加載內(nèi)存中的所有行,然后分批處理它們,而是在從JDBC流傳輸行時(shí)直接處理它們。

TA貢獻(xiàn)1794條經(jīng)驗(yàn) 獲得超8個(gè)贊
而不是Java端的Lists.partition(users,2000),您應(yīng)該將每個(gè)請(qǐng)求的mysql結(jié)果集限制為2000。
select UserPropertyKindId, login from TEST.users limit <offset>, 2000;
更新:正如Raymond Nijland在下面的評(píng)論中提到的,如果偏移量太大,則查詢(xún)速度可能會(huì)大大降低。
一種解決方法可能是使用偏移量,而不是使用偏移量,引入where語(yǔ)句,例如where id> last_user_id。
由于@All_safe在下面進(jìn)行了注釋?zhuān)虼瞬淮嬖谧詣?dòng)增量ID,因此另一個(gè)針對(duì)較大偏移量的解決方法是:僅在子查詢(xún)中獲取主鍵,然后再聯(lián)接回主表。這將強(qiáng)制mysql不執(zhí)行早期行查找,這是大偏移量限制的主要問(wèn)題。
但是您的原始查詢(xún)僅獲取主鍵列,我認(rèn)為早期行查找不適用。

TA貢獻(xiàn)1820條經(jīng)驗(yàn) 獲得超3個(gè)贊
我遇到了類(lèi)似的情況。我正在從一個(gè)MySQL數(shù)據(jù)庫(kù)中讀取數(shù)據(jù),并將其復(fù)制到MS SQL Server數(shù)據(jù)庫(kù)中。不是2億,每天只有400萬(wàn)。但是我在通信鏈接失敗時(shí)也遇到了同樣的錯(cuò)誤消息。我可以通過(guò)設(shè)置PreparedStatement.setFetchSize(Integer.MIN_VALUE);的fetchsize來(lái)解決它。因此,通信鏈接故障消失了。我知道,這不能解決您的列表問(wèn)題。
添加回答
舉報(bào)