spring-projects / spring-projects/spring-data-relational

LazyConnectionDataSourceProxy support in R2DBC

Open
#2,026 3 comments 0 reactions 1 assignee View on GitHub

@mp911de is already working on this.

Since Apr 14, 2025.

status: feedback-provided status: waiting-for-triage
Dominant language
Java
Stars
827
Forks
394
PR merge metrics
No merged PRs in 30d

Description

I would like to route requests to either the master or slave database based on the readOnly attribute of the @Transactional annotation, similar to how it's done in Spring MVC.

However, in R2DBC, there's no component equivalent to LazyConnectionDataSourceProxy.
Because of this, the transaction is not yet initialized at the time TransactionSynchronizationManager is queried, so we cannot determine whether the transaction is read-only.

Is there a specific reason why a LazyConnectionDataSourceProxy-like mechanism hasn't been defined for R2DBC?

I'd love to hear your thoughts on this.
Thanks for all the great work on the project!

The approach you mentioned in https://github.com/spring-projects/spring-data-relational/issues/1261#issuecomment-1621167552 doesn't fit our use case.
This is because the same read query could be executed against both the master and the slave, which we > want to avoid.

MVC example

core component: AbstractRoutingDataSource, LazyConnectionDataSourceProxy

@Bean
public DataSource dataSource(
    @Qualifier("writableDataSource") DataSource writableDataSource,
    @Qualifier("readonlyDataSource") DataSource readonlyDataSource
) {
    final ReadWriteRoutingDataSource routingDataSource = new ReadWriteRoutingDataSource();

    Map<Object, Object> dataSourceMap = new HashMap<>();
    dataSourceMap.put(DataSourceType.WRITABLE, writableDataSource);
    dataSourceMap.put(DataSourceType.READONLY, readonlyDataSource);
    routingDataSource.setTargetDataSources(dataSourceMap);
    routingDataSource.setDefaultTargetDataSource(writableDataSource);
    routingDataSource.afterPropertiesSet();

    return new LazyConnectionDataSourceProxy(routingDataSource);
}

public class ReadWriteRoutingDataSource extends AbstractRoutingDataSource {
    @Override
    protected Object determineCurrentLookupKey() {
        return TransactionSynchronizationManager.isCurrentTransactionReadOnly()
            ? DataSourceType.READONLY
            : DataSourceType.WRITABLE;
    }
}

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.