Browse Source

[spring] Batch update and Java 23 (#9370)

The commit:
 - Use batch update in spring-webflux
 - Upgrade Java 21 to Java 23
 - Increase the connection pool from 256 to 512
 - Upgrade to Spring Boot 3.3.5
Sébastien Deleuze 9 months ago
parent
commit
1f3fb16bc3

+ 1 - 3
frameworks/Java/spring-webflux/pom.xml

@@ -13,14 +13,12 @@
     <parent>
         <groupId>org.springframework.boot</groupId>
         <artifactId>spring-boot-starter-parent</artifactId>
-        <version>3.3.4</version>
+        <version>3.3.5</version>
     </parent>
 
     <properties>
         <java.version>21</java.version>
         <jstachio.version>1.3.6</jstachio.version>
-        <r2dbc-pool.version>1.0.2.RELEASE</r2dbc-pool.version>
-        <r2dbc-postgresql.version>1.0.7.RELEASE</r2dbc-postgresql.version>
     </properties>
 
     <dependencies>

+ 1 - 1
frameworks/Java/spring-webflux/spring-webflux-mongo.dockerfile

@@ -4,7 +4,7 @@ COPY src src
 COPY pom.xml pom.xml
 RUN mvn package -q
 
-FROM bellsoft/liberica-openjre-debian:21
+FROM bellsoft/liberica-openjre-debian:23
 WORKDIR /spring
 COPY --from=maven /spring/target/spring-webflux-benchmark.jar app.jar
 # See https://docs.spring.io/spring-boot/reference/packaging/efficient.html

+ 1 - 1
frameworks/Java/spring-webflux/spring-webflux.dockerfile

@@ -4,7 +4,7 @@ COPY src src
 COPY pom.xml pom.xml
 RUN mvn package -q
 
-FROM bellsoft/liberica-openjre-debian:21
+FROM bellsoft/liberica-openjre-debian:23
 WORKDIR /spring
 COPY --from=maven /spring/target/spring-webflux-benchmark.jar app.jar
 # See https://docs.spring.io/spring-boot/reference/packaging/efficient.html

+ 3 - 1
frameworks/Java/spring-webflux/src/main/java/benchmark/repository/DbRepository.java

@@ -1,5 +1,7 @@
 package benchmark.repository;
 
+import java.util.List;
+
 import benchmark.model.Fortune;
 import benchmark.model.World;
 import reactor.core.publisher.Flux;
@@ -9,7 +11,7 @@ public interface DbRepository {
 
     Mono<World> getWorld(int id);
 
-    Mono<World> findAndUpdateWorld(int id, int randomNumber);
+    Mono<Void> updateWorlds(List<World> worlds);
 
     Flux<Fortune> fortunes();
 }

+ 8 - 9
frameworks/Java/spring-webflux/src/main/java/benchmark/repository/MongoDbRepository.java

@@ -1,16 +1,16 @@
 package benchmark.repository;
 
+import java.util.List;
+
 import benchmark.model.Fortune;
 import benchmark.model.World;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
+
 import org.springframework.context.annotation.Profile;
 import org.springframework.data.mongodb.core.ReactiveMongoOperations;
 import org.springframework.stereotype.Component;
 import reactor.core.publisher.Flux;
 import reactor.core.publisher.Mono;
 
-import static org.springframework.data.mongodb.core.FindAndModifyOptions.options;
 import static org.springframework.data.mongodb.core.query.Criteria.where;
 import static org.springframework.data.mongodb.core.query.Query.query;
 import static org.springframework.data.mongodb.core.query.Update.update;
@@ -31,12 +31,11 @@ public class MongoDbRepository implements DbRepository {
     }
 
     @Override
-    public Mono<World> findAndUpdateWorld(int id, int randomNumber) {
-        return operations.findAndModify(
-                query(where("id").is(id)),
-                update("randomNumber", randomNumber),
-                options().returnNew(true),
-                World.class);
+    public Mono<Void> updateWorlds(List<World> worlds) {
+        return Flux.fromIterable(worlds).flatMap(world -> operations.findAndModify(
+                query(where("id").is(world.id)),
+                update("randomNumber", world.randomnumber),
+                World.class)).then();
     }
 
     @Override

+ 20 - 17
frameworks/Java/spring-webflux/src/main/java/benchmark/repository/R2dbcDbRepository.java

@@ -1,11 +1,17 @@
 package benchmark.repository;
 
+import java.util.List;
+
 import org.springframework.context.annotation.Profile;
 import org.springframework.r2dbc.core.DatabaseClient;
 import org.springframework.stereotype.Component;
 
 import benchmark.model.Fortune;
 import benchmark.model.World;
+import io.r2dbc.spi.Connection;
+import io.r2dbc.spi.ConnectionFactory;
+import io.r2dbc.spi.Result;
+import io.r2dbc.spi.Statement;
 import reactor.core.publisher.Flux;
 import reactor.core.publisher.Mono;
 
@@ -23,28 +29,25 @@ public class R2dbcDbRepository implements DbRepository {
     public Mono<World> getWorld(int id) {
         return databaseClient
                 .sql("SELECT id, randomnumber FROM world WHERE id = $1")
-                .bind("$1", id)
+                .bind(0, id)
                 .mapProperties(World.class)
                 .first();
     }
 
-    private Mono<World> updateWorld(World world) {
-        return databaseClient
-                .sql("UPDATE world SET randomnumber=$2 WHERE id = $1")
-                .bind("$1", world.id)
-                .bind("$2", world.randomnumber)
-                .fetch()
-                .rowsUpdated()
-                .map(count -> world);
-    }
-
-
     @Override
-    public Mono<World> findAndUpdateWorld(int id, int randomNumber) {
-        return getWorld(id).flatMap(world -> {
-            world.randomnumber = randomNumber;
-            return updateWorld(world);
-        });
+    public Mono<Void> updateWorlds(List<World> worlds) {
+        return databaseClient.inConnectionMany(con -> {
+            Statement statement = con.createStatement("UPDATE world SET randomnumber=$2 WHERE id = $1");
+            for (int i = 0; i < worlds.size(); i++) {
+                World world = worlds.get(i);
+                statement.bind(0, world.randomnumber)
+                        .bind(1, world.id);
+                if (i < worlds.size() - 1) {
+                    statement.add();
+                }
+            }
+            return Flux.from(statement.execute());
+        }).flatMap(Result::getRowsUpdated).then();
     }
 
     @Override

+ 11 - 2
frameworks/Java/spring-webflux/src/main/java/benchmark/web/DbHandler.java

@@ -1,5 +1,6 @@
 package benchmark.web;
 
+import java.util.Comparator;
 import java.util.List;
 
 import benchmark.Utils;
@@ -68,8 +69,16 @@ public class DbHandler {
         int queries = parseQueryCount(request.queryParams().getFirst("queries"));
 
         Mono<List<World>> worlds = Flux.fromStream(Utils.randomWorldNumbers().limit(queries).boxed())
-                .flatMap(i -> dbRepository.findAndUpdateWorld(i, Utils.randomWorldNumber()))
-                .collectList();
+                .flatMap(id -> dbRepository.getWorld(id).map(world -> {
+                    int randomNumber;
+                    do {
+                        randomNumber = Utils.randomWorldNumber();
+                    } while (randomNumber == world.randomnumber);
+                    world.randomnumber = randomNumber;
+                    return world;
+                }))
+                .collectSortedList(Comparator.comparingInt(w -> w.id))
+                .flatMap(list -> dbRepository.updateWorlds(list).thenReturn(list));
 
         return ServerResponse.ok()
                 .header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE)

+ 1 - 1
frameworks/Java/spring-webflux/src/main/resources/application.yml

@@ -17,7 +17,7 @@ spring:
     password: ${database.password}
     url: r2dbc:postgresql://${database.host}:${database.port}/${database.name}?loggerLevel=OFF&disableColumnSanitiser=true&assumeMinServerVersion=16&sslmode=disable
     pool:
-      max-size: 256
+      max-size: 512
 
 ---
 spring:

+ 1 - 1
frameworks/Java/spring/pom.xml

@@ -11,7 +11,7 @@
 	<parent>
 		<groupId>org.springframework.boot</groupId>
 		<artifactId>spring-boot-starter-parent</artifactId>
-		<version>3.3.4</version>
+		<version>3.3.5</version>
 	</parent>
 
 	<properties>

+ 1 - 1
frameworks/Java/spring/spring-mongo.dockerfile

@@ -4,7 +4,7 @@ COPY src src
 COPY pom.xml pom.xml
 RUN mvn package -q
 
-FROM bellsoft/liberica-openjre-debian:21
+FROM bellsoft/liberica-openjre-debian:23
 WORKDIR /spring
 COPY --from=maven /spring/target/hello-spring-1.0-SNAPSHOT.jar app.jar
 # See https://docs.spring.io/spring-boot/reference/packaging/efficient.html

+ 1 - 1
frameworks/Java/spring/spring.dockerfile

@@ -4,7 +4,7 @@ COPY src src
 COPY pom.xml pom.xml
 RUN mvn package -q
 
-FROM bellsoft/liberica-openjre-debian:21
+FROM bellsoft/liberica-openjre-debian:23
 WORKDIR /spring
 COPY --from=maven /spring/target/hello-spring-1.0-SNAPSHOT.jar app.jar
 # See https://docs.spring.io/spring-boot/reference/packaging/efficient.html

+ 1 - 1
frameworks/Java/spring/src/main/resources/application.yml

@@ -15,7 +15,7 @@ spring:
     username: ${database.username}
     password: ${database.password}
     hikari:
-      maximum-pool-size: 256
+      maximum-pool-size: 512
 database:
   name: hello_world
   host: tfb-database