I'm trying to configure R2DBC connection to PostgreSQL database with connection pool. I have followed this documentation: https://github.com/r2dbc/r2dbc-pool/blob/main/README.md .
ConnectionFactory connectionFactory = ConnectionFactories.get(ConnectionFactoryOptions.builder()
.option(DRIVER, "pool")
.option(PROTOCOL, "postgresql") // driver identifier, PROTOCOL is delegated as DRIVER by the pool.
.option(HOST, "192.168.1.200")
.option(PORT, 5433)
.option(DATABASE, "XXX")
.option(USER, "XXX")
.option(PASSWORD, "XXX")
.build());
ConnectionPoolConfiguration configuration = ConnectionPoolConfiguration.builder(connectionFactory)
.maxIdleTime(Duration.ofMillis(1000))
.initialSize(10)
.maxSize(100)
.build();
ConnectionPool pool = new ConnectionPool(configuration);
Mono<Connection> connection = pool.create();
return Flux.from(connection)
.flatMap(conn -> conn
.createStatement("SELECT id, name, description FROM assortment")
.execute())
.flatMap(result -> result
.map((row, rowMetadata) ->
new AssortmentItem(
row.get("id", Long.class),
row.get("name", String.class),
row.get("description", String.class))
));
But I don't know how to close connection after query, to get it back to pool. I've tried:
connection.close();
but it doesn't work, try-with-resources to. Without this after 10 calls I got "io.r2dbc.postgresql.ExceptionFactory$PostgresqlNonTransientResourceException" with message "sorry, too many clients already".
How to close connection and get it back to pool in my example? Why I can only call 10 queries from pool (initial pool size) when max pool size is 100?
Here's one way to do it with reactor, inspired by the OracleTestKit
:
pool.create()
.flatMapMany(connection ->
Flux.from(connection.createStatement("SELECT ...").execute())
.flatMap(it -> it.map((r, m) -> new AssortmentItem(...)))
)
.concatWith(Mono.from(connection.close()).cast(AssortmentItem.class))
Other examples are given in this discussion on the mailing list , eg via Flux.usingWhen()
:
Flux.usingWhen(
pool.create(),
c -> c.createStatement("SELECT ...").execute(),
c -> c.close()
)
.flatMap(it -> it.map((r, m) -> r.get("id", Long.class)));
Ultimately, this isn't about R2DBC, but about using your reactive streams API (eg reactor) to correctly sequence the execute()
and close()
operations.
A number of third party APIs are already wrapping R2DBC. jOOQ 3.15 will, too . It will make this particular task a bit easier:
// Inject this into your beans, or whatever
DSLContext ctx = DSL.using(pool);
// jOOQ queries are publishers
Flux.from(ctx.resultQuery("SELECT id, name, description FROM assortment"))
// Use jOOQ's mapping to automatically map fields by reflection
.map(r -> r.into(AssortItem.class));
This isn't using or depending on jOOQ's DSL (though you can also do that, if you like). I imagine that JDBI and other APIs will offer similar simplifications?
Disclaimer: I work for the company behind jOOQ.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.