ぐぐってみると、mariadb-java-clientは2014年頃の1.1.7ではfetch-sizeの挙動が怪しくデータ量など運が悪いとOOMになるケースも多かったようだが、少なくとも3.5.7ではその挙動は無くなっている。
検証内容
docker run --name some-mariadb -e MARIADB_ROOT_PASSWORD=pass -p 3306:3306 mariadb:latest
簡単にメモリを溢れさせるために適当な長さの文字列カラムを持つテーブルを作成。適当な件数をあらかじめ追加しておく。
create table sample ( id SERIAL NOT NULL PRIMARY KEY, name varchar(10000) );
以下の定義だとorg.mariadb.jdbc:mariadb-java-clientは3.5.7となる。
plugins {
id 'java'
id 'org.springframework.boot' version '4.0.1'
id 'io.spring.dependency-management' version '1.1.7'
}
group = 'com.example'
version = '0.0.1-SNAPSHOT'
java {
sourceCompatibility = '17'
}
configurations {
compileOnly {
extendsFrom annotationProcessor
}
}
repositories {
mavenCentral()
}
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-jdbc'
implementation 'org.apache.commons:commons-lang3'
compileOnly 'org.projectlombok:lombok'
developmentOnly 'org.springframework.boot:spring-boot-devtools'
annotationProcessor 'org.projectlombok:lombok'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
runtimeOnly 'org.mariadb.jdbc:mariadb-java-client' //3.5.7
}
tasks.named('test') {
useJUnitPlatform()
}
簡単にOOM起こさせるために最大メモリを極端に小さくする。
-Xmx10m
1.まずは以下のように全件読み込もうとしてOOMの発生を確認する。
JdbcClient c = JdbcClient.create(ds);
List<DataLoaddd> list = c.sql("select id, name from sample").query(DataLoaddd.class).list();
System.out.println(list.size());
2.次に、fetch-sizeを指定してstreamではOOMが発生しない事を確認する。
JdbcClient c = JdbcClient.create(ds);
c.sql("select id, name from sample")
.withFetchSize(1)
.query(DataRecored.class)
.stream()
.forEach(d -> {
System.out.println(d);
});
3.加えて、読み込んだ行をupdateするトランザクション処理を追加してもOOMが発生しない事を確認する。
JdbcClient c = JdbcClient.create(ds);
c.sql("select id, name from sample")
.withFetchSize(1)
.query(DataRecored.class)
.stream()
.forEach(d -> {
System.out.println(d);
TransactionDefinition t = new DefaultTransactionDefinition();
TransactionStatus transaction = m.getTransaction(t);
int update = c.sql(
"update sample set name = '" + RandomStringUtils.insecure()
.nextAlphanumeric(10000) + "' where id = " + d.id()).update();
m.commit(transaction);
});
ここでmariadb-java-clientを超古い1.1.7に変更すると、1・2・3いずれもOOMになる。
runtimeOnly 'org.mariadb.jdbc:mariadb-java-client:1.1.7'
というわけで、2014年頃とかの1.1.7はまともにfetch-sizeが機能していなかったが現代の3.5.7とかはちゃんと機能していそうである。少なくとも、良くあるfetch across commitは書けそうではある。
余談
はじめてMariaDBとそのJDBCを使う事になったが「mariadb bulk fetch」とかでぐぐると上手くいかないとか何とかのブログが何件かヒットして不安になった。ただ、いずれも2015年前後のかなり古いもの。それで、とりあえず単純な動作だけでも確認しとくか、となった。こんくらいなら問題無さそうなのでとりあえず安心している。