#125 - First draft of R2DBC benchmarks.
TODOs: - Review interaction with the JDBC auto-configuration - Wait for tcp protocol of H2 to be supported - Wait for Postgres to accept credentialless connections (see [0]) [0] https://github.com/r2dbc/r2dbc-postgresql/issues/125
This commit is contained in:
committed by
Mark Paluch
parent
ba8d634fd8
commit
bdf518841b
@@ -13,6 +13,10 @@
|
||||
<artifactId>spring-data-benchmark-relational</artifactId>
|
||||
|
||||
<name>Spring Data Benchmarks - Relational Microbenchmarks</name>
|
||||
|
||||
<properties>
|
||||
<spring-boot-data-r2dbc.version>0.1.0.BUILD-SNAPSHOT</spring-boot-data-r2dbc.version>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
|
||||
@@ -41,6 +45,28 @@
|
||||
<artifactId>postgresql</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- R2DBC -->
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot.experimental</groupId>
|
||||
<artifactId>spring-boot-starter-data-r2dbc</artifactId>
|
||||
<version>${spring-boot-data-r2dbc.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.r2dbc</groupId>
|
||||
<artifactId>r2dbc-h2</artifactId>
|
||||
<version>0.8.0.M8</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.r2dbc</groupId>
|
||||
<artifactId>r2dbc-postgresql</artifactId>
|
||||
<version>0.8.0.M8</version>
|
||||
</dependency>
|
||||
|
||||
<!-- Mocking -->
|
||||
|
||||
<dependency>
|
||||
<groupId>org.mockito</groupId>
|
||||
<artifactId>mockito-core</artifactId>
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
/*
|
||||
* Copyright 2019 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.data.microbenchmark.r2dbc;
|
||||
|
||||
import lombok.AccessLevel;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.Value;
|
||||
import lombok.experimental.Wither;
|
||||
|
||||
import org.springframework.data.annotation.Id;
|
||||
import org.springframework.data.annotation.PersistenceConstructor;
|
||||
|
||||
/**
|
||||
* @author Oliver Drotbohm
|
||||
*/
|
||||
@Value
|
||||
@RequiredArgsConstructor(access = AccessLevel.PACKAGE, onConstructor = @__(@PersistenceConstructor))
|
||||
class Book {
|
||||
|
||||
@Wither(AccessLevel.PACKAGE) @Id Long id;
|
||||
String title;
|
||||
int pages;
|
||||
|
||||
public Book(String title, int pages) {
|
||||
|
||||
this.id = null;
|
||||
this.title = title;
|
||||
this.pages = pages;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,105 @@
|
||||
/*
|
||||
* Copyright 2019 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.data.microbenchmark.r2dbc;
|
||||
|
||||
import java.util.function.Function;
|
||||
|
||||
import org.openjdk.jmh.annotations.Benchmark;
|
||||
import org.openjdk.jmh.annotations.Param;
|
||||
import org.openjdk.jmh.annotations.Setup;
|
||||
import org.openjdk.jmh.infra.Blackhole;
|
||||
import org.springframework.context.ConfigurableApplicationContext;
|
||||
import org.springframework.data.microbenchmark.common.AbstractMicrobenchmark;
|
||||
import org.springframework.data.r2dbc.core.DatabaseClient;
|
||||
|
||||
import io.r2dbc.spi.Row;
|
||||
|
||||
/**
|
||||
* Benchmark for R2DBC and Spring Data R2DBC
|
||||
*
|
||||
* @author Oliver Drotbohm
|
||||
*/
|
||||
public class R2dbcBenchmark extends AbstractMicrobenchmark {
|
||||
|
||||
private static final String FIND_ALL_SQL = "SELECT id, title, pages FROM Book";
|
||||
private static final String BY_TITLE_SQL = FIND_ALL_SQL + " where title = :title";
|
||||
|
||||
@Param({ /* "postgres", */ "h2-in-memory" /*, "h2" */ })
|
||||
String profile;
|
||||
|
||||
private DatabaseClient operations;
|
||||
private Function<Row, Book> mapper;
|
||||
|
||||
private R2dbcBookRepository repository;
|
||||
|
||||
@Setup
|
||||
public void setUp() {
|
||||
|
||||
R2dbcFixture fixture = new R2dbcFixture(profile);
|
||||
|
||||
ConfigurableApplicationContext context = fixture.getContext();
|
||||
|
||||
this.operations = context.getBean(DatabaseClient.class);
|
||||
this.mapper = row -> new Book(row.get("id", Long.class), row.get("title", String.class), row.get("pages", Integer.class));
|
||||
|
||||
this.repository = context.getBean(R2dbcBookRepository.class);
|
||||
}
|
||||
|
||||
@Benchmark
|
||||
public void findByTitle(Blackhole sink) {
|
||||
|
||||
sink.consume(operations.execute(BY_TITLE_SQL) //
|
||||
.bind("title", "title0") //
|
||||
.map(mapper)
|
||||
.one() //
|
||||
.block());
|
||||
}
|
||||
|
||||
@Benchmark
|
||||
public void findAll(Blackhole sink) {
|
||||
|
||||
sink.consume(operations.execute(FIND_ALL_SQL) //
|
||||
.map(mapper) //
|
||||
.all() //
|
||||
.collectList() //
|
||||
.block());
|
||||
}
|
||||
|
||||
@Benchmark
|
||||
public void repositoryFindByTitle(Blackhole sink) {
|
||||
sink.consume(repository.findByTitle("title0").block());
|
||||
}
|
||||
|
||||
@Benchmark
|
||||
public void repositoryFindTransactionalByTitle(Blackhole sink) {
|
||||
sink.consume(repository.findTransactionalByTitle("title0").block());
|
||||
}
|
||||
|
||||
@Benchmark
|
||||
public void repositoryFindAll(Blackhole sink) {
|
||||
sink.consume(repository.findAll().collectList().block());
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
|
||||
new R2dbcFixture("postgres") //
|
||||
.getContext() //
|
||||
.getBean(R2dbcBookRepository.class) //
|
||||
.findAll() //
|
||||
.collectList() //
|
||||
.block();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* Copyright 2019 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.data.microbenchmark.r2dbc;
|
||||
|
||||
import org.springframework.data.r2dbc.repository.R2dbcRepository;
|
||||
import org.springframework.data.r2dbc.repository.query.Query;
|
||||
import org.springframework.transaction.annotation.Propagation;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import reactor.core.publisher.Flux;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
/**
|
||||
* A repository for {@link Book} instances.
|
||||
*
|
||||
* @author Oliver Drotbohm
|
||||
*/
|
||||
interface R2dbcBookRepository extends R2dbcRepository<Book, Long> {
|
||||
|
||||
static final String BY_TITLE = "SELECT id, title, pages FROM Book where title = :title";
|
||||
|
||||
@Transactional(propagation = Propagation.NOT_SUPPORTED)
|
||||
Flux<Book> findAll();
|
||||
|
||||
@Query(BY_TITLE)
|
||||
Mono<Book> findByTitle(String title);
|
||||
|
||||
@Transactional(readOnly = true)
|
||||
@Query(BY_TITLE)
|
||||
Mono<Book> findTransactionalByTitle(String title);
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
/*
|
||||
* Copyright 2019 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.data.microbenchmark.r2dbc;
|
||||
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.r2dbc.R2dbcProperties;
|
||||
import org.springframework.context.ConfigurableApplicationContext;
|
||||
import org.springframework.core.io.ClassPathResource;
|
||||
import org.springframework.core.io.Resource;
|
||||
import org.springframework.data.microbenchmark.FixtureUtils;
|
||||
import org.springframework.data.r2dbc.connectionfactory.init.ResourceDatabasePopulator;
|
||||
|
||||
import io.r2dbc.spi.ConnectionFactory;
|
||||
import lombok.Getter;
|
||||
|
||||
/**
|
||||
* Test fixture for JDBC and Spring Data JDBC benchmarks.
|
||||
*
|
||||
* @author Oliver Drotbohm
|
||||
*/
|
||||
public class R2dbcFixture {
|
||||
|
||||
private final @Getter ConfigurableApplicationContext context;
|
||||
|
||||
public R2dbcFixture(String database) {
|
||||
|
||||
this.context = FixtureUtils.createContext(R2dbcApplication.class, "r2dbc", database);
|
||||
|
||||
R2dbcProperties properties = context.getBean(R2dbcProperties.class);
|
||||
String platform = properties.getPlatform();
|
||||
|
||||
Resource schema = new ClassPathResource(String.format("schema-%s.sql", platform));
|
||||
Resource data = new ClassPathResource(String.format("data-%s.sql", platform));
|
||||
|
||||
ResourceDatabasePopulator populator = new ResourceDatabasePopulator(schema, data);
|
||||
populator.execute(context.getBean(ConnectionFactory.class)).block();
|
||||
}
|
||||
|
||||
|
||||
@SpringBootApplication (exclude = {
|
||||
DataSourceAutoConfiguration.class
|
||||
})
|
||||
static class R2dbcApplication {}
|
||||
}
|
||||
@@ -1,2 +1,3 @@
|
||||
spring.datasource.platform=h2
|
||||
|
||||
spring.r2dbc.platform=h2
|
||||
|
||||
@@ -4,3 +4,8 @@ spring.datasource.password=
|
||||
spring.datasource.platform=h2
|
||||
spring.datasource.initialization-mode=always
|
||||
|
||||
spring.r2dbc.url=r2dbc:h2:tcp://localhost:9092/~/benchmark
|
||||
spring.r2dbc.username=sa
|
||||
spring.r2dbc.password=
|
||||
spring.r2dbc.platform=h2
|
||||
spring.r2dbc.initialization-mode=always
|
||||
|
||||
@@ -2,3 +2,6 @@ spring.datasource.url=jdbc:postgresql://localhost:5432/benchmark
|
||||
spring.datasource.platform=postgres
|
||||
spring.datasource.initialization-mode=always
|
||||
|
||||
spring.r2dbc.url=r2dbc:postgresql://localhost:5432/benchmark
|
||||
spring.r2dbc.platform=postgres
|
||||
spring.r2dbc.initialization-mode=always
|
||||
@@ -0,0 +1,2 @@
|
||||
spring.data.jpa.repositories.enabled=false
|
||||
spring.data.jdbc.repositories.enabled=false
|
||||
Reference in New Issue
Block a user