当R2DBC与Flyway和JDBC一起使用时,如何选择正确的TransactionManager



设置:

  • micronaut 3.7.2
  • micronaut数据3.8.1,micronaut-data-r2dbc,r2dbc-postgresql 0.9.2
  • Flyway 8.5.13,micronaut jdbc hikari,micronat Flyway 5.4.1,postgresql 42.5.0
  • 测试容器(jdbc、r2dbc、postgresql(1.17.5
  • io.micronaut.test-resources 3.6.2

测试配置(conf4k(:

datasources {
default {
dialect=POSTGRES
options {
currentSchema=default
}
}
}
r2dbc {
datasources {
default {
dialect=POSTGRES
options {
currentSchema=default
}
}
}
}
flyway {
datasources {
default {
enabled=true
locations="classpath:databasemigrations"
schemas=["default"]
create-schemas=true
}
}
}
test-resources {
containers {
postgres {
image-name="postgres:12.12"
hostnames=["localhost"]
}
}
}

前提条件:

为了使Flyway和micronaut数据使用相同的数据库和测试容器,两者的数据源需要命名相似。

问题:

由于JDBC和R2DBC同时使用,因此创建了同步和反应式TransactionManagers bean,当我使用@Transactional:时,我会收到以下错误

Multiple possible bean candidates found: [io.micronaut.transaction.jdbc.DataSourceTransactionManager, io.micronaut.transaction.sync.SynchronousFromReactiveTransactionManager]

想法:

我想,我可以用@TransactionalAdvice解决这个问题,但由于两个数据源需要有相同的名称,所以这是不可能的。我尝试以不同的方式命名数据源,但根本不起作用。

您可以尝试将Jdbc(默认(和Flyway(Flyway取决于Jdbc Datasouce(的数据源名称更改为另一个名称,然后在您的Jdbc存储库中,使用@TransactionalAdvice来选择它。

在同一个项目中,我有一个使用Flyway和R2dbc的Micronaut示例。

但我还没有尝试过@Transactional,对于事务处理,我使用的是R2dbcOperations.withTransaction,效果很好。

public Mono<Long> deleteAll() {
var sql = "DELETE  FROM customers";
return Mono.from(
r2dbcOperations.withTransaction(status ->
Mono.just(status.getConnection())
.flatMap(connection -> Mono
.from(connection.createStatement(sql).execute())
.flatMap(result -> Mono.from(result.getRowsUpdated()))
)
)
);
}

在这里查看我的Micronaut R2dbc示例,希望它有帮助。

正如Hantsy在他的文章中提到的,在Flyway最终支持R2DBC之前,使用R2dbcOperations#withTransaction()以编程方式添加事务是一种临时的解决方法。请在这里投赞成票。

由于我使用了Kotlin和Coroutines,所以该代码是次优的,但对于一个希望短暂的解决方案来说还可以。要在Kotlin中使用它,必须将传递给withTransaction的函数体封装在mono{}中。

最新更新