Skip to content

How to route R2DBC calls to different data sources? #1261

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
danilodeLuca opened this issue Jun 17, 2022 · 3 comments
Closed

How to route R2DBC calls to different data sources? #1261

danilodeLuca opened this issue Jun 17, 2022 · 3 comments
Assignees
Labels
for: stackoverflow A question that's better suited to stackoverflow.com

Comments

@danilodeLuca
Copy link

i'm trying to use 2 different data sources in the same project: readWrite(RW) and readOnly(RO), each one having its own instance host.
To do that I have configured RW data source as default, using spring-r2dbc properties and dependency, and it works fine.
But when trying to configure a RO it does not have any property support, so I manually configured the connectionFactory and DatabaseClient with RO properties, like the following code.

Configuring this new connection and databaseClient (RO) for some reason the connection pool is using this config instead of just using the default configurable in the application (the pool is composed by RW and RO connection). Is there some way to force pool to ignore it? Or a way to do that?

Versions:
io.r2dbc:r2dbc-postgresql:0.8.11.RELEASE
io.r2dbc:r2dbc-pool:0.8.8.RELEASE
org.springframework.boot:spring-boot-starter-data-r2dbc:2.6.6

image

Spring application.properties:
image

@spring-projects-issues spring-projects-issues added the status: waiting-for-triage An issue we've not yet triaged label Jun 17, 2022
@mp911de mp911de self-assigned this Jun 27, 2022
@hantsy
Copy link

hantsy commented Aug 26, 2022

if possible to select the two datasources automatically and implements read write operations separate in one method. Eg, perform query on the read-only connections, and do modifications on another connections.

@mp911de mp911de changed the title r2dbc - Support for different datasources - like rw/ro How to route R2DBC calls to different data sources? Jul 5, 2023
@mp911de mp911de added for: stackoverflow A question that's better suited to stackoverflow.com and removed status: waiting-for-triage An issue we've not yet triaged labels Jul 5, 2023
@mp911de
Copy link
Member

mp911de commented Jul 5, 2023

You can use AbstractRoutingConnectionFactory along with Reactor's context feature to set up routing. Here's a snippet that shows the setup. The code will print the database schema (using H2 here) to show which database you're using.

	@Bean
	CloseableConnectionFactory rw() {
		return H2ConnectionFactory.inMemory("rw");
	}

	@Bean
	CloseableConnectionFactory ro() {
		return H2ConnectionFactory.inMemory("ro");
	}

	@Bean
	CloseableConnectionFactory def() {
		return H2ConnectionFactory.inMemory("def");
	}

	@Bean
	AbstractRoutingConnectionFactory router(CloseableConnectionFactory rw, CloseableConnectionFactory ro,
			CloseableConnectionFactory def) {

		AbstractRoutingConnectionFactory router = new AbstractRoutingConnectionFactory() {
			@Override
			protected Mono<Object> determineCurrentLookupKey() {
				return Mono.deferContextual(contextView -> {

					if (contextView.hasKey("TYPE")) {
						return Mono.just(contextView.get("TYPE"));
					}

					return Mono.empty();
				});
			}
		};

		router.setTargetConnectionFactories(Map.of("RW", rw, "RO", ro));
		router.setDefaultTargetConnectionFactory(def);

		return router;
	}

	@Bean
	CommandLineRunner commandLineRunner(AbstractRoutingConnectionFactory router) {

		R2dbcTransactionManager tm = new R2dbcTransactionManager(router);

		return args -> {

			TransactionalOperator transactionalOperator = TransactionalOperator.create(tm);

			DatabaseClient.create(router)
					.sql("CALL CURRENT_CATALOG")
					.fetch()
					.all()
					.doOnNext(System.out::println)
					.as(transactionalOperator::transactional)
					.contextWrite(Context.of("TYPE", "RO"))
					.blockLast();
		};
	}

@mp911de mp911de closed this as completed Jul 5, 2023
@danilodeLuca
Copy link
Author

Thats amazing! I didn't know about it, I will try to implement it soon
Thank you @mp911de

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
for: stackoverflow A question that's better suited to stackoverflow.com
Projects
None yet
Development

No branches or pull requests

4 participants