рдХреЛрд░реБрдЯрд┐рди рд╕реЗ рдбреЗрдЯрд╛рдмреЗрд╕ рддрдХ рдкреНрд░рддрд┐рдХреНрд░рд┐рдпрд╛рд╢реАрд▓ рдкрд╣реБрдВрдЪ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдиреЗ рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рдПрдХ рд▓реЗрдЦред рд╡рд╕рдВрдд рд╕рдм рдХреБрдЫ рд╕рд░рд▓ рдХрд░рддрд╛ рд╣реИ, рд▓реЗрдХрд┐рди рдпрд╣ рдЖрд╡реЗрджрди рдХреА рд╡рд╛рд╕реНрддрд╡рд┐рдХ рдкреНрд░рдХреНрд░рд┐рдпрд╛рдУрдВ рдХреА рд╕рдордЭ рдХреЛ рдкреНрд░рднрд╛рд╡рд┐рдд рдирд╣реАрдВ рдХрд░рддрд╛ рд╣реИред рдкреНрд░рджрд░реНрд╢рди рдХреЗ рд▓рд┐рдП, рдХреЗрдЯрд░ рдлреНрд░реЗрдорд╡рд░реНрдХ рдХреЛ рдЪреБрдирд╛ рдЧрдпрд╛ рдерд╛ (рд╕рд┐рд░реНрдл рдЗрд╕рд▓рд┐рдП рдХрд┐ рдореБрдЭреЗ рдпрд╣ рджреЗрдЦрдирд╛ рдкрд╕рдВрдж рд╣реИ рдХрд┐ рдЬреЗрдЯрдмреНрд░реЗрди рдХреНрдпрд╛ рдХрд░рддрд╛ рд╣реИ), рдЬреЛ рдЧрд╣рди рд░реВрдк рд╕реЗ рдХреЛрд░рдЯрд╛рдЗрди рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рддрд╛ рд╣реИ - рддрд╛рдХрд┐ рд░рд┐рдПрдХреНрдЯрд┐рд╡ рд╕реНрдЯреНрд░реАрдо рдФрд░ рдЗрди рд╕рдорд╛рди рдХреЛрд░рдЖрдЙрдЯреЛрдВ рдХреЗ рд╕рдВрдпреЛрдЬрди рдХрд╛ рдХрд╛рд░реНрдп рдмреНрдпрд╛рдЬ рдЬреЛрдбрд╝рддрд╛ рд╣реИред рдЗрд╕ рдкреНрд░рдХреНрд░рд┐рдпрд╛ рдореЗрдВ, рдпрд╣ рд╕реНрдкрд╖реНрдЯ рд╣реЛ рдЧрдпрд╛ рдХрд┐ рдЬреЛ рдХреБрдЫ рд╣реЛ рд░рд╣рд╛ рдерд╛ рд╡рд╣ рд╕рдордЭ рдореЗрдВ рдЖрдиреЗ рд╡рд╛рд▓реА рдЕрдирд┐рд╡рд╛рд░реНрдп рдкреНрд░реЛрдЧреНрд░рд╛рдорд┐рдВрдЧ рдХреЗ рд▓рд┐рдП рдПрдХ рд╕рдордЭ рд╕реЗ рдкрд░реЗ рдЬреЗрдЯ рд╕реНрдЯреНрд░реАрдо рдХреЗ рдкрд░рд┐рд╡рд░реНрддрди рдХрд╛ рдПрдХ рд╕реНрдкрд╖реНрдЯ рдЙрджрд╛рд╣рд░рдг рдерд╛, рдЬрд┐рд╕ рдкрд░ рд╣рдордиреЗ рдПрдХ рдХреБрддреНрддрд╛ рдЦрд╛рдпрд╛ рдерд╛ред рдореБрдЭреЗ рдЬреЗрдЯ рдЪреЗрди рдкрд╕рдВрдж рд╣реИ, рд▓реЗрдХрд┐рди рд╕реЗрдирд╛ рдХреЗ рдЖрджреЗрд╢ рд╕реЗ рдкреНрдпрд╛рд░ рдХрд░рдиреЗ рд╡рд╛рд▓реЛрдВ рдХреЛ рдЦреБрд╢ рдХреНрдпреЛрдВ рдирд╣реАрдВ рдХрд░рддреЗ?
рдЬреЗрдЯ рдЕрдиреБрдкреНрд░рдпреЛрдЧреЛрдВ рдиреЗ рдХрдИ рдбреЗрд╡рд▓рдкрд░реНрд╕ рдХреЗ рджрд┐рд▓ рдФрд░ рдирд╕реЛрдВ рдХреЛ рдЬреАрдд рд▓рд┐рдпрд╛ рд╣реИ, рдФрд░ рдпреЗ рд╕реЗрдЯ рд╕реНрдкрд╖реНрдЯ рд░реВрдк рд╕реЗ рдкреНрд░рддрд┐рдЪреНрдЫреЗрдж рдХрд░рддреЗ рд╣реИрдВред рд╡реЗ рдФрд░ рднреА рдЕрдзрд┐рдХ рд▓рдЧрд╛рдП рдЧрдП рд╣реЛрддреЗ, рдпрджрд┐ рд╡рд┐рд╢рд┐рд╖реНрдЯ рд╕рдореБрджрд╛рдпреЛрдВ рдХреЗ рд░рдЪрдирд╛рдХрд╛рд░реЛрдВ рдХреЗ рдорди рдХреА рд╡рд┐рд╢реБрджреНрдз рдзрд╛рд░рд╛ рдХреЛ рд╕реБрдкрд╛рдЪреНрдп рдкреБрд╕реНрддрдХрд╛рд▓рдпреЛрдВ рдореЗрдВ рдврд╛рд▓рдиреЗ рд╡рд╛рд▓реЗ рд╕рдореБрджрд╛рдпреЛрдВ рдХреЗ рдкреНрд░рдпрд╛рд╕реЛрдВ рдХреЗ рд▓рд┐рдП рдирд╣реАрдВред рдпрд╣ 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())
.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()
.collectList()
.awaitFirst()
convertData@
""
TODO()
} finally {
connection
.close()
.awaitFirstOrNull()
}
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
)
}
, JDBC .
map Reactor, ReactiveStream Java Stream, R2DBC.
convertData@
result.flatMap {
it
.map(Tables.DB::ofRow)
.toFlux()
.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 рдбреАрдПрд╕рдПрд▓ рдХреЗ рдорд╛рдзреНрдпрдо рд╕реЗ рджреЗ рд╕рдХрддреЗ рд╣реИрдВред
рдЬрд╛рдБрдЪ - рдкрд░рд┐рдгрд╛рдо
рдЖрдк рдкреНрд░рддрд┐рдХреНрд░рд┐рдпрд╛рд╢реАрд▓ рдкреНрд░рд╡рд╛рд╣ рдХреЗ рд╕рд╛рде рдХреЛрд░рдЯрд╛рдЗрди рдмрдирд╛ рд╕рдХрддреЗ рд╣реИрдВ, рд▓реЗрдХрд┐рди рдЖрдкрдХреЛ рдкреНрд░рддрд┐рдХреНрд░рд┐рдпрд╛рд╢реАрд▓ рдФрд░ рдЕрдирд┐рд╡рд╛рд░реНрдп рд╢реИрд▓рд┐рдпреЛрдВ рдХреЗ рдмреАрдЪ рд╕реНрд╡рд┐рдЪ рдХрд░рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИ - рдЕрдзрд┐рдорд╛рдирддрдГ рдХрдо рдЕрдХреНрд╕рд░ рдФрд░ рдПрдХ рд╢реИрд▓реА рдХрд╛ рдкрд╛рд▓рди рдХрд░рдиреЗ рдХрд╛ рдкреНрд░рдпрд╛рд╕ рдХрд░реЗрдВред
рдХреЗрд╡рд▓ рдПрдХ рд╡рд╕рдВрдд рдирд╣реАрдВ!
рдкреНрд░рддрд┐рдХреНрд░рд┐рдпрд╛рддреНрдордХ рдбреЗрдЯрд╛рдмреЗрд╕ рдПрдХреНрд╕реЗрд╕ рд╕реНрдкреНрд░рд┐рдВрдЧ рдбреЗрдЯрд╛ рдЬреЗрдкреАрдП рдореЗрдХрдЕрдк рдХреЗ рдмрд╛рдж рдХреЗ рд░реВрдк рдореЗрдВ рд╕реБрдВрджрд░ рдирд╣реАрдВ рд╣реИ, рд▓реЗрдХрд┐рди рдЖрдк рдЗрд╕рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВред