Jetbrains KTor рдФрд░ R2DBC рдХреЗ рдЙрджрд╛рд╣рд░рдг рдкрд░ рдкреНрд░рддрд┐рдХреНрд░рд┐рдпрд╛рд╢реАрд▓ рдбреЗрдЯрд╛ рдХреЗ рдкреНрд░рддрд┐ рджреГрд╖реНрдЯрд┐рдХреЛрдг

рдХреЛрд░реБрдЯрд┐рди рд╕реЗ рдбреЗрдЯрд╛рдмреЗрд╕ рддрдХ рдкреНрд░рддрд┐рдХреНрд░рд┐рдпрд╛рд╢реАрд▓ рдкрд╣реБрдВрдЪ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдиреЗ рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рдПрдХ рд▓реЗрдЦред рд╡рд╕рдВрдд рд╕рдм рдХреБрдЫ рд╕рд░рд▓ рдХрд░рддрд╛ рд╣реИ, рд▓реЗрдХрд┐рди рдпрд╣ рдЖрд╡реЗрджрди рдХреА рд╡рд╛рд╕реНрддрд╡рд┐рдХ рдкреНрд░рдХреНрд░рд┐рдпрд╛рдУрдВ рдХреА рд╕рдордЭ рдХреЛ рдкреНрд░рднрд╛рд╡рд┐рдд рдирд╣реАрдВ рдХрд░рддрд╛ рд╣реИред рдкреНрд░рджрд░реНрд╢рди рдХреЗ рд▓рд┐рдП, рдХреЗрдЯрд░ рдлреНрд░реЗрдорд╡рд░реНрдХ рдХреЛ рдЪреБрдирд╛ рдЧрдпрд╛ рдерд╛ (рд╕рд┐рд░реНрдл рдЗрд╕рд▓рд┐рдП рдХрд┐ рдореБрдЭреЗ рдпрд╣ рджреЗрдЦрдирд╛ рдкрд╕рдВрдж рд╣реИ рдХрд┐ рдЬреЗрдЯрдмреНрд░реЗрди рдХреНрдпрд╛ рдХрд░рддрд╛ рд╣реИ), рдЬреЛ рдЧрд╣рди рд░реВрдк рд╕реЗ рдХреЛрд░рдЯрд╛рдЗрди рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рддрд╛ рд╣реИ - рддрд╛рдХрд┐ рд░рд┐рдПрдХреНрдЯрд┐рд╡ рд╕реНрдЯреНрд░реАрдо рдФрд░ рдЗрди рд╕рдорд╛рди рдХреЛрд░рдЖрдЙрдЯреЛрдВ рдХреЗ рд╕рдВрдпреЛрдЬрди рдХрд╛ рдХрд╛рд░реНрдп рдмреНрдпрд╛рдЬ рдЬреЛрдбрд╝рддрд╛ рд╣реИред рдЗрд╕ рдкреНрд░рдХреНрд░рд┐рдпрд╛ рдореЗрдВ, рдпрд╣ рд╕реНрдкрд╖реНрдЯ рд╣реЛ рдЧрдпрд╛ рдХрд┐ рдЬреЛ рдХреБрдЫ рд╣реЛ рд░рд╣рд╛ рдерд╛ рд╡рд╣ рд╕рдордЭ рдореЗрдВ рдЖрдиреЗ рд╡рд╛рд▓реА рдЕрдирд┐рд╡рд╛рд░реНрдп рдкреНрд░реЛрдЧреНрд░рд╛рдорд┐рдВрдЧ рдХреЗ рд▓рд┐рдП рдПрдХ рд╕рдордЭ рд╕реЗ рдкрд░реЗ рдЬреЗрдЯ рд╕реНрдЯреНрд░реАрдо рдХреЗ рдкрд░рд┐рд╡рд░реНрддрди рдХрд╛ рдПрдХ рд╕реНрдкрд╖реНрдЯ рдЙрджрд╛рд╣рд░рдг рдерд╛, рдЬрд┐рд╕ рдкрд░ рд╣рдордиреЗ рдПрдХ рдХреБрддреНрддрд╛ рдЦрд╛рдпрд╛ рдерд╛ред рдореБрдЭреЗ рдЬреЗрдЯ рдЪреЗрди рдкрд╕рдВрдж рд╣реИ, рд▓реЗрдХрд┐рди рд╕реЗрдирд╛ рдХреЗ рдЖрджреЗрд╢ рд╕реЗ рдкреНрдпрд╛рд░ рдХрд░рдиреЗ рд╡рд╛рд▓реЛрдВ рдХреЛ рдЦреБрд╢ рдХреНрдпреЛрдВ рдирд╣реАрдВ рдХрд░рддреЗ?


рдЬреЗрдЯ рдЕрдиреБрдкреНрд░рдпреЛрдЧреЛрдВ рдиреЗ рдХрдИ рдбреЗрд╡рд▓рдкрд░реНрд╕ рдХреЗ рджрд┐рд▓ рдФрд░ рдирд╕реЛрдВ рдХреЛ рдЬреАрдд рд▓рд┐рдпрд╛ рд╣реИ, рдФрд░ рдпреЗ рд╕реЗрдЯ рд╕реНрдкрд╖реНрдЯ рд░реВрдк рд╕реЗ рдкреНрд░рддрд┐рдЪреНрдЫреЗрдж рдХрд░рддреЗ рд╣реИрдВред рд╡реЗ рдФрд░ рднреА рдЕрдзрд┐рдХ рд▓рдЧрд╛рдП рдЧрдП рд╣реЛрддреЗ, рдпрджрд┐ рд╡рд┐рд╢рд┐рд╖реНрдЯ рд╕рдореБрджрд╛рдпреЛрдВ рдХреЗ рд░рдЪрдирд╛рдХрд╛рд░реЛрдВ рдХреЗ рдорди рдХреА рд╡рд┐рд╢реБрджреНрдз рдзрд╛рд░рд╛ рдХреЛ рд╕реБрдкрд╛рдЪреНрдп рдкреБрд╕реНрддрдХрд╛рд▓рдпреЛрдВ рдореЗрдВ рдврд╛рд▓рдиреЗ рд╡рд╛рд▓реЗ рд╕рдореБрджрд╛рдпреЛрдВ рдХреЗ рдкреНрд░рдпрд╛рд╕реЛрдВ рдХреЗ рд▓рд┐рдП рдирд╣реАрдВред рдпрд╣ R2DBC рд╡рд┐рдирд┐рд░реНрджреЗрд╢ рдФрд░ рд╕реНрдкреНрд░рд┐рдВрдЧ (рдмреВрдЯ) рдврд╛рдВрдЪреЗ рдХреЗ рд╕рд╛рде рд╣реБрдЖ - рдбреЗрд╡рд▓рдкрд░ рдкрд╣рд▓реЗ рд╕реЗ рд╣реА рдкрд░рд┐рдЪрд┐рдд рдкреНрд░рддрд┐рдХреНрд░рд┐рдпрд╛ рдбреЗрдЯрд╛ рдкреНрд░рдХрд╛рд░реЛрдВ рдХреЗ рд╕рд╛рде рдкрд░рд┐рдЪрд┐рдд рд╕реНрдкреНрд░рд┐рдВрдЧ рдбреЗрдЯрд╛ рдПрдкреАрдЖрдИ рджреЗрдЦ рд╕рдХрддрд╛ рд╣реИред рд╣рд╛рд▓рд╛рдБрдХрд┐, рд╕реНрдкреНрд░рд┐рдВрдЧ рдХрд╛ рдЙрдкрдпреЛрдЧ рди рдХрд░рдиреЗ рдХреЗ рдХреБрдЫ рдХрд╛рд░рдг рд╣реИрдВ: рдЖрдк рд╕реНрдкреНрд░рд┐рдВрдЧ рдирд╣реАрдВ рдЪрд╛рд╣рддреЗ рд╣реИрдВ рдФрд░ рдЖрдк рдХреБрдЫ рдирдпрд╛ рдЪрд╛рд╣рддреЗ рд╣реИрдВред рдЦреИрд░, рдЕрднреА рднреА рд╡рд┐рд░рд╛рд╕рдд рдХреЛрдб рд╣реИ, рд▓реЗрдХрд┐рди рдЗрд╕ рдорд╛рдорд▓реЗ рдореЗрдВ рдЖрдкрдХреЗ рдкрд╛рд╕ рдкреНрд░рддрд┐рдХреНрд░рд┐рдпрд╛рд╢реАрд▓ рдбреЗрдЯрд╛ рдкрд╣реБрдВрдЪ рдХреА рд╕рдВрднрд╛рд╡рдирд╛ рдирд╣реАрдВ рд╣реИред


рдЗрд╕ рдорд╛рдорд▓реЗ рдореЗрдВ, рдЖрдкрдХреЛ R2DBC рдХреЛ рдмрд┐рдирд╛ рд▓рд╛рдЗрд╕реЗрдВрд╕ рдХреЗ рджреЗрдЦрдирд╛ рд╣реЛрдЧрд╛ ред рдФрд░ рдпрд╣ рдЙрдореНрдореАрдж рдХреА рдЬрд╛рдПрдЧреА рдХрд┐ рд╣рдо рддреИрдпрд╛рд░ рдврд╛рдВрдЪреЗ рдореЗрдВ рдЬреЛ рдкреЗрд╢рдХрд╢ рдХрд░рддреЗ рд╣реИрдВ рдЙрд╕рд╕реЗ рдмрд╣реБрдд рдЕрд▓рдЧ рд╣реИрдВ - рдареАрдХ рдЙрд╕реА рддрд░рд╣ рдЬреИрд╕реЗ рдХрд┐ рдЬреЗрдбреАрдмреАрд╕реА рд╕реНрдкреНрд░рд┐рдВрдЧ рдбреЗрдЯрд╛ рдЬреЗрдкреАрдП рд╕реЗ рдЕрд▓рдЧ рд╣реИред рдкреНрд▓рд╕ рдкреНрд░рддрд┐рдХреНрд░рд┐рдпрд╛ред рдФрд░ рдкреНрд░рддрд┐рдХреНрд░рд┐рдпрд╛рд╢реАрд▓ рдзрд╛рд░рд╛рдУрдВ рд╡рд┐рдирд┐рд░реНрджреЗрд╢ рдХреЗ рдЕрдиреБрд╕рд╛рд░ рдкреНрд░рддрд┐рдХреНрд░рд┐рдпрд╛рд╢реАрд▓рддрд╛ред рдФрд░ рд╣рдо рдХреЛрд░рдЯрд╛рдЗрди рд╕реБрдирддреЗ рд╣реИрдВред рднрд╡рд┐рд╖реНрдп рдХрд┐рд╕ рддрд░рд╣ рдХрд╛ рд╣реИ рдФрд░ рдЕрднреА рднреА рдЙрдиреНрд╣реЗрдВ рдлрд┐рд░ рд╕реЗ рд▓рд┐рдЦрдирд╛ рд╣реИред


рдЖрдк рдореБрдЦреНрдп рд╡рд┐рдзрд┐ рд╕реЗ рдореИрдиреНрдпреБрдЕрд▓ рд░реВрдк рд╕реЗ рдХреЛрд░рдЖрдЙрдЯ рдХрд░рдирд╛ рд╢реБрд░реВ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ , рд▓реЗрдХрд┐рди рдЖрдЗрдП рдХрд▓реНрдкрдирд╛ рдХрд░рдиреЗ рдХреА рдХреЛрд╢рд┐рд╢ рдХрд░реЗрдВ рдХрд┐ рд╣рдореЗрдВ рд╡рд╛рд╕реНрддрд╡ рдореЗрдВ рд╕рдорд╛рдирддрд╛ рдФрд░ рдкреНрд░рддрд┐рд╕реНрдкрд░реНрдзрд╛ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИ - рдЕрд░реНрдерд╛рдд, рдЙрдЪреНрдЪ рднрд╛рд░ (рдкреНрд░рддрд┐ рдШрдВрдЯреЗ рдПрдХ рдЕрдиреБрд░реЛрдз!) рдФрд░ рд╣рдордиреЗ рдЧрдВрднреАрд░рддрд╛ рд╕реЗ рдЗрд╕реЗ рдмрд┐рдирд╛ рд╡рд╕рдВрдд рдХреЗ рд▓рд┐рдЦрдиреЗ рдХрд╛ рдлреИрд╕рд▓рд╛ рдХрд┐рдпрд╛ред рд▓реЗрдХрд┐рди рдпрд╣рд╛рдВ, рдпрд╣ рдкрддрд╛ рдЪрд▓рд╛ рд╣реИ, рд╣рдорд╛рд░реЗ рдкрд╛рд╕ рдкреВрд░реА рддрд░рд╣ рд╕реЗ рдХреЛрдЯрд▓рд┐рди рдореЗрдВ рд▓рд┐рдЦрд╛ рдЧрдпрд╛ рдПрдХ рд╣рд▓реНрдХрд╛ рдПрдирд╛рд▓реЙрдЧ рд╣реИ, рдФрд░ рдпрд╣рд╛рдВ рддрдХ тАЛтАЛрдХрд┐ рднрд╛рд╖рд╛ рдХреЗ рд░рдЪрдирд╛рдХрд╛рд░реЛрдВ рд╕реЗ рднреА, рдФрд░ рдпрд╣рд╛рдВ рддрдХ тАЛтАЛрдХрд┐ рд╣рдо рдЬрд┐рд╕ рдХреЛрд░рдЯрд╛рдЗрди рдкрд░ рд╕рдкрдирд╛ рджреЗрдЦрддреЗ рд╣реИрдВред


рд╣рдо рдПрдХ рдкреНрд░реЛрдЬреЗрдХреНрдЯ рддреИрдпрд╛рд░ рдХрд░ рд░рд╣реЗ рд╣реИрдВ


, - ( IntelliJ IDEA).


https://start.ktor.io :


  • Call Logging: ,
  • Routing: (endpoint URI)
  • Gson: .

, тАФ OAuth, JWT, LDAP , .


. , IntelliJ IDEA Community Edition.



H2, build.gradle


    implementation "io.r2dbc:r2dbc-h2:0.8.1.RELEASE"


    implementation "io.r2dbc:r2dbc-pool:0.8.1.RELEASE"

Reactive Streams, R2DBC , Reactor Kotlin, :


    implementation "io.projectreactor.kotlin:reactor-kotlin-extensions:1.0.2.RELEASE"
    implementation "org.jetbrains.kotlinx:kotlinx-coroutines-reactor:1.3.5"

: JVM 1.8. , - native Java. .


build.gradle


tasks.withType(org.jetbrains.kotlin.gradle.tasks.KotlinCompile).configureEach {
    kotlinOptions {
        jvmTarget = "1.8"
    }
}


тАФ Application.kt, . , , :


fun Application.module(testing: Boolean = false) {
    //       
initDatabase@

    //   

applicationStarted@
    //       

boringStandardInitialization@
    //   ,   
    install(ContentNegotiation) {
        gson {
        }
    }

    install(CallLogging) {
        level = Level.INFO
        filter { call -> call.request.path().startsWith("/") }
    }

    routing {
        get("/") {
showTables@
            //       
            call.respondText("HELLO WORLD!", contentType = ContentType.Text.Plain)
        }

        get("/json/gson") {
showPool@            
            //      
            call.respond(mapOf("hello" to "world"))
        }
    }
}

, application.conf ktor.deployment port . , :


        watch = [ /home/votez/cc/ktor-reactive-db/build/classes/kotlin/main/ ]

тАФ , devtools, . , .



initDatabase ( ) .


initDatabase@
    "" // ,        
    val connectionFactory = H2ConnectionFactory(
        H2ConnectionConfiguration.builder()
            .inMemory("users")
            .property(H2ConnectionOption.DB_CLOSE_DELAY, "-1")
            .build()
    )

    val poolConfig = ConnectionPoolConfiguration.builder(connectionFactory)
        .maxIdleTime(10.seconds.toJavaDuration()) //     @ExperimentalTime
        .maxSize(20)
        .build()

    val pool = ConnectionPool(poolConfig)

@ExperimentalTime тАФ API.


, ( ) . , . :


applicationStarted@
    //       
    environment.monitor.subscribe(ApplicationStarted) {
        launch {
            val defer : Mono<Int> = pool.warmup()
            defer.awaitFirst()                             //   
            log.debug("Pool is hot, welcome!") //    
        }
    }

тАФ launch . , , тАФ , . - ! "" (awaitFirst Kotlin), . : Reactor- Mono Flux ? . " -"? , тАФ . тАФ . , , Reactor RxJava . тАФ "!" " !". , , - . тАФ RxJava Reactor тАФ !


, . , .



CRUD , , , H2 : TABLES. - :


data class Tables(    val catalog: String?,    val schema: String?,    val tableName: String?,    val tableType: String?,    val storageType: String?,    val id: String?,    val typeName: String?,    val tableClass: String?,    val rowCountEstimate: Long?) 

typealias , IDE


typealias R2DBCResult = io.r2dbc.spi.Result

. , R2DBC:


get("/tables") {
            showTables@
            //       
            ""
            val connection = pool.create().awaitSingle() //    -  
            val list = try { 
                val result: List<R2DBCResult> = connection.createStatement(
                        """
                            select 
                                TABLE_CATALOG, TABLE_SCHEMA, TABLE_NAME, TABLE_TYPE, STORAGE_TYPE, SQL, ID, TYPE_NAME, TABLE_CLASS, ROW_COUNT_ESTIMATE
                            from 
                                INFORMATION_SCHEMA.TABLES
                                """.trimIndent()
                    )
                    .execute()  //    
                    .toFlux()   //      Reactor Flux
                    .collectList()  //             
                    .awaitFirst()   // ,    -    .
   convertData@
                ""
                TODO() //    ,    
            } finally {
                connection
                    .close()    //   
                    .awaitFirstOrNull() //   null -    .
            }

            call.respond(list)
        }

, Reactor map/flatMap . map/flatMap , , . finally тАФ ( ) doFinally . , README conn.close(), . тАФ , тАФ . , map await, .


awaitFirstOrNull() Mono, onNext() .

, тАФ , , .



R2DBC - (map) . companion object -:


 companion object DB{
        fun ofRow(r: Row, unused: RowMetadata) = Tables(
            r.get("TABLE_CATALOG", String::class.java),
            r.get("TABLE_SCHEMA", String::class.java),
            r.get("TABLE_NAME", String::class.java),
            r.get("TABLE_TYPE", String::class.java),
            r.get("STORAGE_TYPE", String::class.java),
            r.get("ID", Integer::class.java)?.toString(),
            r.get("TYPE_NAME", String::class.java),
            r.get("TABLE_CLASS", String::class.java),
            r.get("ROW_COUNT_ESTIMATE", java.lang.Long::class.java)?.toLong() ?: 0 //     Java ,     
        )
    }

, JDBC .


map Reactor, ReactiveStream Java Stream, R2DBC.


   convertData@
                result.flatMap {//      .  -   ,    
                    it
                        .map(Tables.DB::ofRow)  //     
                        .toFlux()               //      Reactor Flux 
                        .collectList()          //             
                        .awaitFirst()          // ,    -    .
                }

, :


curl http://localhost:8080/tables

рдпрджрд┐ JSON рдмрджрд╕реВрд░рдд рд╣реИ, рддреЛ рдпрд╣ рдПрдкреНрд▓рд┐рдХреЗрд╢рди рдХреЗ рдЧреЙрди рд╕реЗрдХреНрд╢рди ( setPrettyPrinting ) рдореЗрдВ рдХреЙрдиреНрдлрд╝рд┐рдЧрд░ рдХрд┐рдпрд╛ рдЧрдпрд╛ рд╣реИ ред


рд╣рдо рдкреВрд▓ рдХреЗ рдЖрдВрдХрдбрд╝реЗ рджреЗрддреЗ рд╣реИрдВ


рдЕрдЪреНрдЫреА рддрд░рд╣ рд╕реЗ рдФрд░ рд╕реБрдВрджрд░рддрд╛ рдХреЗ рд▓рд┐рдП (рдЪреВрдВрдХрд┐ рд╣рдо рдореИрдЯреНрд░рд┐рдХреНрд╕ рдХреЗ рдорд╛рдирдХ рдореЙрдбреНрдпреВрд▓ рдХреЛ рдХрдиреЗрдХреНрдЯ рдирд╣реАрдВ рдХрд░рддреЗ рдереЗ) рд╣рдо рдкреВрд▓ рдЖрдБрдХрдбрд╝реЛрдВ рдХреЛ рджреЗрдЦрдиреЗ рдХреЗ рд▓рд┐рдП рдПрдХ рдмрд┐рдВрджреБ рдЬреЛрдбрд╝ рджреЗрдВрдЧреЗред рдЯреЗрдореНрдкреНрд▓реЗрдЯ рдЗрдВрдЬрди рд╣рдорд╛рд░реЗ рд▓рд┐рдП рдмрд╣реБрдд рдЕрдЪреНрдЫрд╛ рд╣реИ, рдХреНрдпреЛрдВрдХрд┐ рд╣рдорд╛рд░реА рднрд╛рд╖рд╛ рдЙрдкрдХрд░рдг рд╣рдореЗрдВ рдЗрд╕рдХреА рдЕрдиреБрдорддрд┐ рджреЗрддреЗ рд╣реИрдВ:


        get("/pool") {
            showPool@
            //      
            call.respondText {
                (pool.metrics.map {
                    """
                Max allocated size:                 ${it.maxAllocatedSize}
                Max pending size  :                 ${it.maxPendingAcquireSize}
                Acquired size     :                 ${it.acquiredSize()}
                Pending acquire size:               ${it.pendingAcquireSize()}
                Allocated size    :                 ${it.allocatedSize()}
                Idle size         :                 ${it.idleSize()}\n
            """.trimIndent()
                }.orElse("NO METRICS"))
            }
        }

рдмреЗрд╢рдХ, рдпрджрд┐ рдЖрдк рдЪрд╛рд╣реЗрдВ, рддреЛ рдЖрдк рдЗрд╕реЗ HTML рдбреАрдПрд╕рдПрд▓ рдХреЗ рдорд╛рдзреНрдпрдо рд╕реЗ рджреЗ рд╕рдХрддреЗ рд╣реИрдВред


рдЬрд╛рдБрдЪ - рдкрд░рд┐рдгрд╛рдо


рдЖрдк рдкреНрд░рддрд┐рдХреНрд░рд┐рдпрд╛рд╢реАрд▓ рдкреНрд░рд╡рд╛рд╣ рдХреЗ рд╕рд╛рде рдХреЛрд░рдЯрд╛рдЗрди рдмрдирд╛ рд╕рдХрддреЗ рд╣реИрдВ, рд▓реЗрдХрд┐рди рдЖрдкрдХреЛ рдкреНрд░рддрд┐рдХреНрд░рд┐рдпрд╛рд╢реАрд▓ рдФрд░ рдЕрдирд┐рд╡рд╛рд░реНрдп рд╢реИрд▓рд┐рдпреЛрдВ рдХреЗ рдмреАрдЪ рд╕реНрд╡рд┐рдЪ рдХрд░рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИ - рдЕрдзрд┐рдорд╛рдирддрдГ рдХрдо рдЕрдХреНрд╕рд░ рдФрд░ рдПрдХ рд╢реИрд▓реА рдХрд╛ рдкрд╛рд▓рди рдХрд░рдиреЗ рдХрд╛ рдкреНрд░рдпрд╛рд╕ рдХрд░реЗрдВред


рдХреЗрд╡рд▓ рдПрдХ рд╡рд╕рдВрдд рдирд╣реАрдВ!


рдкреНрд░рддрд┐рдХреНрд░рд┐рдпрд╛рддреНрдордХ рдбреЗрдЯрд╛рдмреЗрд╕ рдПрдХреНрд╕реЗрд╕ рд╕реНрдкреНрд░рд┐рдВрдЧ рдбреЗрдЯрд╛ рдЬреЗрдкреАрдП рдореЗрдХрдЕрдк рдХреЗ рдмрд╛рдж рдХреЗ рд░реВрдк рдореЗрдВ рд╕реБрдВрджрд░ рдирд╣реАрдВ рд╣реИ, рд▓реЗрдХрд┐рди рдЖрдк рдЗрд╕рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВред


All Articles