an endeavor to bring a reactive programming API to SQL databases. • ΧϯϑΝϨϯεظؒதʢ11/4ʙ11/8ʣ·ͩGAͰͳ ͔ͬͨͷͰ͕͢ɺ12্݄०ʹGAʹͳΓ·ͨ͠ • https://r2dbc.io/2019/12/02/r2dbc-0-8-0-goes-ga
H2 Database ※ first-party https://github.com/r2dbc • Community • MySQL • https://github.com/mirromutth/r2dbc-mysql • https://github.com/jasync-sql/jasync-sql • SAP HANA • Google Cloud Spanner
RSocket is a binary protocol for use on byte stream transports such as TCP, WebSockets, and Aeron(UDP). • marking͞Μͷࢿྉ͕ຊޠͰॻ͔Ε͍͔ͯͯΓ͍͢ Ͱ͢ • https://docs.google.com/presentation/d/1ygSM85- RQ3NZjCg6RaZ52mGzxbWiItVwzlCpr1vaWBw/ edit#slide=id.g75f375afa0_0_0
@ConfigurationProperties("example.kotlin") data class KotlinExampleProperties(val name: String, val description: String, val myService: MyService) { data class MyService(val apiToken: String, val uri: URI) }
Flowcold streamsͰɺFlow͕collect͞ΕΔ·Ͱflow builderͷίʔυ࣮ߦ͞Εͳ͍ • FlowReactive Streamsͱ૬ޓӡ༻࡞༻ͯ͠ɺbackpressueΛαϙʔτ͢Δ https://kotlinlang.org/docs/reference/coroutines/flow.html fun foo(): Flow<Int> = flow { // flow builder for (i in 1..3) { delay(100) // pretend we are doing something useful here emit(i) // emit next value } } fun main() = runBlocking { // Collect the flow foo().collect { value -> println(value) } }
with a nice balance between imperative and declarative style • Context interoperability between Coroutines and Reactor • Allows to support Reactive transactions and security
fun findAll(): Flow<User> = operations.query<User>().flow() suspend fun findOne(id: String): User = operations.query<User>() .matching(query(where(User::id).isEqualTo(id))) .awaitOne() suspend fun insert(user: User): User = operations.insert<User>().oneAndAwait(user) suspend fun update(user: User): User = operations.update<User>() .replaceWith(user) .asType<User>() .findReplaceAndAwait() }
} data class Customer(val id: Int, val name: String) @Service class CustomerService(private val jdbcTemplate: JdbcTemplate) { fun findAll(): List<Customer> = jdbcTemplate.query("SELECT * FROM customer") { rs, _ -> Customer(rs.getInt("id"), rs.getString("name")) } }
id = integer("id").autoIncrement() val name = varchar("name", 255) override val primaryKey = PrimaryKey(id) } data class Customer(val id: Int, val name: String) TQSJOHFYQPTFEHFOFSBUFEEEMUSVFʹ͢ΕɺҎԼͷ%%-͕࣮ߦ͞ΕΔ $3&"5&5"#-&*'/05&9*454 $6450.&34 *%*/5"650@*/$3&.&/513*."3:,&: /".&7"3$)"3 /05/6--
UserService userService; @GetMapping("/users/{id}") public Mono<User> getUser(@PathVariable long id) { return userService.getUser(id); } } @Data @NoArgsConstructor @AllArgsConstructor public class User { private long id; private String name; }