반응형
개요
Reactive Relational Database Connectivity
SQL database에서 Reactive programming을 지원하기 위해 디자인된 새로운 Open Specification
R2DBC를 쉽게 사용할 수 있도록 ORM의 사용법을 참고하여 설계하였으나, ORM Framework에서 제공하는 다양한 기능을 제공하지 않음.
특징
Based on the Reactive Streams specification.
- provides a fully-reactive non-blocking API.
Works with relational databases.
- JDBC의 Blocking 특성과 달리, R2DBC를 사용하면 Reactive API를 사용하여 SQL database로 작업할 수 있다.
Supports scalable solutions.
- Reactive Stream을 사용하면 기존의 "연결 당 하나의 스레드"모델에서보다 강력하고 확장 가능한 접근 방식이 가능하다.
Provides an open specification.
- R2DBC 는 open specification이며 드라이버 공급업체가 spec을 구현하고 클라이언트가 사용할 SPI(Service Provider Interface) 제공합니다.
- R2DBC는 최소한의 SPI를 목표로 한다.
구현체
clickhouse-r2dbc - R2DBC wrapper of async Java client for ClickHouse.
cloud-spanner-r2dbc - driver for Google Cloud Spanner.
jasync-sql - R2DBC wrapper for Java & Kotlin Async Database Driver for MySQL and PostgreSQL (written in Kotlin).
oracle-r2dbc - native driver implemented for Oracle.
r2dbc-h2 - native driver implemented for H2 as a test database.
r2dbc-mariadb - native driver implemented for MariaDB.
r2dbc-mssql - native driver implemented for Microsoft SQL Server.
r2dbc-mysql - native driver implemented for MySQL (previously mirromutth/r2dbc-mysql).
r2dbc-postgresql - native driver implemented for PostgreSQL.
SPI History ~ 1.0
0.8
- initial version
0.9
- Extended transaction definitions
- Improved Bind Parameter declararation
- Consumption of OUT Parameters
- Consumption of Result Segments
- Lifecycle extension
- Refinement of Option
- Refinement of RowMetadata
- Lock Wait and Statement Timeouts
- Refined Exceptions for Readable.get(…) and Statement.bind(…)
1.0
- Revised Result.getRowsUpdated() signature
- 1.0 스펙 중 이전 버전이랑 하위호환이 안되게 하는 주범, update 시 update row를 Long -> Integer로 변경해서, update(save) 시 classCastException이 발생한다.
- Removed RowMetadata.getColumnNames() method
- TCK Extensions
Spring Data R2DBC
Spring Data R2DBC version | imported R2DBC SPI version | 주요 기능 |
1.0.0 | 0.8 | initial major version |
1.1.0 | 0.8.1 | r2dbcEntityTemplate 기능 추가 query derivation 추가 |
1.2.0 | 0.8.3 | r2dbcAuditing 추가 @Value support support Oracle R2DBC Driver |
1.3.0 | 0.8.4 | Query By Example 기능 추가 |
1.4.0 | 0.8.5 | upgrade dependency |
1.5.0 | 0.9.1 | upgrade dependency |
3.0.0 | 1.0.0 | spring boot 3 대응 |
Spring Boot Starter Data R2DBC version | Spring Data R2DBC version |
2.3.2 | 1.1.2 |
2.4.0 | 1.2.1 |
2.5.0 | 1.3.1 |
2.6.0 | 1.4.0 |
2.7.0 | 1.5.0 |
3.0.0 | 3.0.0 |
MySQL, MariaDB Driver
관련 드라이버
DB Type | Driver | develop by | Desc |
Mysql | jasync-sql | jasync-sql | 코틀린으로 개발된 드라이버 MySQL, PostgreSQL 지원 |
r2dbc-mysql | mirrormutth | 최초의 mysql r2dbc driver 구현체 현재는 개발 중단 |
|
r2dbc-mysql | asyncer-io | mysql 5.5, 5.6, 5.7, 8.0 호환 r2dbc-spi 1.0까지 호환 |
|
MariaDB | mariadb-connector-r2dbc | mariadb-corp | MariaDB 공식 r2dbc 지원 드라이버 |
MySQL 계열 사용 시 공식드라이버인 MariaDB를 사용하는 것이 안정적 일 듯하다
주저리주저리
- 신규 프로젝트에서 R2DBC 사용 도중 update 시 driver에서 오류가 올라와서 부랴부랴 알아봄.
- SPI 1.0 버전이 나온 것까진 알고 있었는데 interface상 하위호환이 안될 줄은 상상도 못 함...
- 일단 버전에 맞는 mariaDB 구현체를 사용해서 해결한 상태.
- 이슈 해결 후 조사한 게 억울해서 블로그에 정리
이슈 stacktrace
20230421 14:59:18.570 [db-sql-netty-thread-2] ERROR o.s.b.a.w.r.e.AbstractErrorWebExceptionHandler - [695cf522-1] 500 Server Error for HTTP PUT "/dev/data"
java.lang.ClassCastException: class java.lang.Long cannot be cast to class java.lang.Integer (java.lang.Long and java.lang.Integer are in module java.base of loader 'bootstrap')
at java.base/java.util.stream.Collectors.lambda$summingInt$19(Collectors.java:673)
Suppressed: reactor.core.publisher.FluxOnAssembly$OnAssemblyException:
Error has been observed at the following site(s):
*__checkpoint ⇢ Handler org.springframework.web.reactive.function.server.RouterFunctionDsl$PUT$2@10647471 [DispatcherHandler]
*__checkpoint ⇢ com.pbear.mainfunctionalserver.common.log.LoggingWebFilter [DefaultWebFilterChain]
*__checkpoint ⇢ HTTP PUT "/dev/data" [ExceptionHandlingWebHandler]
Original Stack Trace:
at java.base/java.util.stream.Collectors.lambda$summingInt$19(Collectors.java:673)
at reactor.core.publisher.MonoStreamCollector$StreamCollectorSubscriber.onNext(MonoStreamCollector.java:132)
at reactor.core.publisher.FluxFlatMap$FlatMapMain.tryEmitScalar(FluxFlatMap.java:489)
at reactor.core.publisher.FluxFlatMap$FlatMapMain.onNext(FluxFlatMap.java:422)
at reactor.core.publisher.FluxMap$MapSubscriber.onNext(FluxMap.java:122)
at reactor.core.publisher.FluxOnErrorResume$ResumeSubscriber.onNext(FluxOnErrorResume.java:79)
at reactor.core.publisher.FluxMap$MapSubscriber.onNext(FluxMap.java:122)
at reactor.core.publisher.FluxConcatMap$ConcatMapImmediate.innerNext(FluxConcatMap.java:282)
at reactor.core.publisher.FluxConcatMap$ConcatMapInner.onNext(FluxConcatMap.java:863)
at reactor.core.publisher.Operators$MonoSubscriber.complete(Operators.java:1839)
at reactor.core.publisher.MonoCompletionStage.lambda$subscribe$0(MonoCompletionStage.java:96)
at java.base/java.util.concurrent.CompletableFuture.uniHandle(CompletableFuture.java:930)
at java.base/java.util.concurrent.CompletableFuture$UniHandle.tryFire(CompletableFuture.java:907)
at java.base/java.util.concurrent.CompletableFuture.postComplete(CompletableFuture.java:506)
at java.base/java.util.concurrent.CompletableFuture.complete(CompletableFuture.java:2073)
at com.github.jasync.sql.db.util.FutureUtilsKt.success(FutureUtils.kt:16)
at com.github.jasync.sql.db.mysql.MySQLConnection.succeedQueryPromise$lambda-12(MySQLConnection.kt:361)
at java.base/java.util.Optional.ifPresent(Optional.java:183)
at com.github.jasync.sql.db.mysql.MySQLConnection.succeedQueryPromise(MySQLConnection.kt:360)
at com.github.jasync.sql.db.mysql.MySQLConnection.onOk(MySQLConnection.kt:227)
at com.github.jasync.sql.db.mysql.codec.MySQLConnectionHandler.channelRead0(MySQLConnectionHandler.kt:125)
at io.netty.channel.SimpleChannelInboundHandler.channelRead(SimpleChannelInboundHandler.java:99)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:444)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:420)
at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:412)
at io.netty.handler.codec.ByteToMessageDecoder.fireChannelRead(ByteToMessageDecoder.java:346)
at io.netty.handler.codec.ByteToMessageDecoder.channelRead(ByteToMessageDecoder.java:318)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:444)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:420)
at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:412)
at io.netty.channel.DefaultChannelPipeline$HeadContext.channelRead(DefaultChannelPipeline.java:1410)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:440)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:420)
at io.netty.channel.DefaultChannelPipeline.fireChannelRead(DefaultChannelPipeline.java:919)
at io.netty.channel.nio.AbstractNioByteChannel$NioByteUnsafe.read(AbstractNioByteChannel.java:166)
at io.netty.channel.nio.NioEventLoop.processSelectedKey(NioEventLoop.java:788)
at io.netty.channel.nio.NioEventLoop.processSelectedKeysOptimized(NioEventLoop.java:724)
at io.netty.channel.nio.NioEventLoop.processSelectedKeys(NioEventLoop.java:650)
at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:562)
at io.netty.util.concurrent.SingleThreadEventExecutor$4.run(SingleThreadEventExecutor.java:997)
at io.netty.util.internal.ThreadExecutorMap$2.run(ThreadExecutorMap.java:74)
at java.base/java.lang.Thread.run(Thread.java:834)
REFERENCE
https://docs.spring.io/spring-data/r2dbc/docs/current/reference/html/
https://r2dbc.io/spec/1.0.0.RELEASE/spec/html/#changes
https://github.com/spring-projects/spring-data-commons/wiki/Release-Trains
반응형
'개발 일지' 카테고리의 다른 글
브라우저와 Redirect (feat. XMLHttpRequest) (0) | 2023.05.19 |
---|---|
Redis 설치 (ubuntu) (0) | 2023.04.26 |
Mysql data directory 변경 (0) | 2023.04.19 |
Gradle 이란 (0) | 2023.04.18 |
Flutter & Dart 개발환경 구성 (feat. IntelliJ) (0) | 2023.04.16 |