Vertx
Модуль предоставляет реализацию репозиториев на основе Vertx реактивного протокола работы с базой данных.
Подключение¶
Зависимость build.gradle
:
Модуль:
Зависимость build.gradle.kts
:
Модуль:
Также требуется предоставить реализацию драйвера как зависимость версии не выше 4.3.8
В отдельных случаях как например с PostgreSQL, требуется также добавить зависимость
Конфигурация¶
Пример полной конфигурации, описанной в классе VertxDatabaseConfig
(указаны примеры значений или значения по умолчанию):
db {
connectionUri = "postgresql://localhost:5432/postgres" //(1)!
username = "postgres" //(2)!
password = "postgres" //(3)!
poolName = "kora" //(4)!
maxPoolSize = 10 //(5)!
connectionTimeout = "10s" //(6)!
acquireTimeout = "0s" //(7)!
idleTimeout = "10m" //(8)!
cachePreparedStatements = true //(9)!
initializationFailTimeout = "0s" //(10)!
readinessProbe = false //(11)!
telemetry {
logging {
enabled = false //(12)!
}
metrics {
enabled = true //(13)!
slo = [ 1, 10, 50, 100, 200, 500, 1000, 2000, 5000, 10000, 20000, 30000, 60000, 90000 ] //(14)!
}
tracing {
enabled = true //(15)!
}
}
}
- URI подключения к базе данных (обязательный)
- Имя пользователя для подключения (обязательный)
- Пароль пользователя для подключения (обязательный)
- Имя набора соединений к базе данных (обязательный)
- Максимальный размер набора соединений к базе данных
- Максимальное время на установку соединения
- Максимальное время на получение соединения из набора соединений (по умолчанию отсутвует)
- Максимальное время на простой соединения
- Кэшировать ли подготовленные запросы
- Максимальное время ожидания инициализации соединения при старте сервиса (по умолчанию отсутвует)
- Включить ли пробу готовности для соединения базы данных
- Включает логгирование модуля (по умолчанию
false
) - Включает метрики модуля (по умолчанию
true
) - Настройка SLO для DistributionSummary метрики
- Включает трассировку модуля (по умолчанию
true
)
db:
connectionUri = "postgresql://localhost:5432/postgres" #(1)!
username: "postgres" #(2)!
password: "postgres" #(3)!
poolName: "kora" #(4)!
maxPoolSize: 10 #(5)!
connectionTimeout: "10s" #(6)!
acquireTimeout: "10s" #(7)!
idleTimeout: "10m" #(8)!
cachePreparedStatements: true #(9)!
initializationFailTimeout: "0s" #(10)!
readinessProbe: false #(11)!
telemetry:
logging:
enabled: false #(12)!
metrics:
enabled: true #(13)!
slo: [ 1, 10, 50, 100, 200, 500, 1000, 2000, 5000, 10000, 20000, 30000, 60000, 90000 ] #(14)!
tracing:
enabled: true #(15)!
- URI подключения к базе данных (обязательный)
- Имя пользователя для подключения (обязательный)
- Пароль пользователя для подключения (обязательный)
- Имя набора соединений к базе данных (обязательный)
- Максимальный размер набора соединений к базе данных
- Максимальное время на установку соединения
- Максимальное время на получение соединения из набора соединений (по умолчанию отсутвует)
- Максимальное время на простой соединения
- Кэшировать ли подготовленные запросы
- Максимальное время ожидания инициализации соединения при старте сервиса (по умолчанию отсутвует)
- Включить ли пробу готовности для соединения базы данных
- Включает логгирование модуля (по умолчанию
false
) - Включает метрики модуля (по умолчанию
true
) - Настройка SLO для DistributionSummary метрики
- Включает трассировку модуля (по умолчанию
true
)
Можно также настроить Netty транспорт.
Использование¶
Конвертация¶
Возможно переопределять преобразование различных частей сущности и параметров запроса, для этого Kora предоставляет специальные интерфейсы.
Результат¶
Если требуется преобразовать результат в ручную, предлагается использовать VertxRowSetMapper
:
final class ResultMapper implements VertxRowSetMapper<List<UUID>> {
@Override
public List<UUID> apply(RowSet<Row> rows) {
// код преобразования
}
}
@Repository
public interface EntityRepository extends VertxRepository {
@Mapping(ResultMapper.class)
@Query("SELECT id FROM entities")
Mono<List<UUID>> getIds();
}
Строка¶
Если требуется преобразовать строку в ручную, предлагается использовать VertxRowMapper
:
final class RowMapper implements VertxRowMapper<UUID> {
@Override
public UUID apply(Row row) {
return UUID.fromString(rs.get(0, String.class));
}
}
@Repository
public interface EntityRepository extends VertxRepository {
@Mapping(RowMapper.class)
@Query("SELECT id FROM entities")
Flux<UUID> findAll();
}
Колонка¶
Если требуется преобразовать значение колонки в ручную, предлагается использовать VertxResultColumnMapper
:
public final class ColumnMapper implements VertxResultColumnMapper<UUID> {
@Override
public UUID apply(Row row, int index) {
return UUID.fromString(row.get(String.class, index));
}
}
@Table("entities")
public record Entity(@Mapping(ColumnMapper.class) @Id UUID id, String name) { }
@Repository
public interface EntityRepository extends VertxRepository {
@Query("SELECT id, name FROM entities")
Flux<Entity> findAll();
}
class ColumnMapper : VertxResultColumnMapper<UUID> {
override fun apply(row: Row, index: Int): UUID {
return UUID.fromString(row.get(String.class, index))
}
}
@Table("entities")
data class Entity(
@Id @Mapping(ColumnMapper::class) val id: UUID,
val name: String
)
@Repository
interface EntityRepository : VertxRepository {
@Query("SELECT id, name FROM entities")
fun findAll(): Flux<Entity>
}
Параметр¶
Если требуется преобразовать значение параметра запроса в ручную, предлагается использовать VertxParameterColumnMapper
:
public final class ParameterMapper implements VertxParameterColumnMapper<UUID> {
@Override
public Object apply(@Nullable UUID value) {
return value.toString();
}
}
@Repository
public interface EntityRepository extends VertxRepository {
@Query("SELECT id, name FROM entities WHERE id = :id")
Flux<Entity> findById(@Mapping(ParameterMapper.class) UUID id);
}
class ParameterMapper : VertxParameterColumnMapper<UUID?> {
override fun apply(value: UUID?): Any {
return value.toString()
}
}
@Repository
interface EntityRepository : VertxRepository {
@Query("SELECT id, name FROM entities WHERE id = :id")
fun findById(@Mapping(ParameterMapper::class) id: UUID): Flux<Entity>
}
Поддерживаемые типы¶
Список поддерживаемых типов для аргументов/возвращаемых значений из коробки
- void
- boolean / Boolean
- short / Short
- int / Integer
- long / Long
- double / Double
- float / Float
- Buffer
- String
- BigDecimal
- BigInteger
- UUID
- LocalTime
- LocalDateTime
Транзакции¶
Для выполнения ручных запросов в Kora есть интерфейс ru.tinkoff.kora.database.vertx.VertxConnectionFactory
,
который предоставляется в методе в рамках контракта VertxRepository
.
Все методы репозитория вызванные в рамках лямбды транзакции будут выполнены в этой самой транзакции.
Для того чтобы выполнять запросы транзакционно, можно использовать контракт inTx
:
@Component
public final class SomeService {
private final EntityRepository repository;
public SomeService(EntityRepository repository) {
this.repository = repository;
}
public Mono<List<Entity>> saveAll(Entity one, Entity two) {
return repository.getVertxConnectionFactory().inTx(connection -> {
// do some work
return repository.insert(one) //(1)!
.zipWith(repository.insert(two), //(2)!
(r1, r2) -> List.of(one, two));
});
}
}
- Будет выполнено в рамках транзакции либо откатится если вся лямбра выкинет исключение
- Будет выполнено в рамках транзакции либо откатится если вся лямбра выкинет исключение
@Component
class SomeService(private val repository: EntityRepository) {
fun saveAll(
one: Entity,
two: Entity
): Mono<List<Entity>> {
return repository.getVertxConnectionFactory.inTx {
repository.insert(one).zipWith(repository.insert(two)) //(1)!
{ r1: UpdateCount, r2: UpdateCount -> listOf(one, two) }
}
}
}
- Будет выполнено в рамках транзакции либо откатится если вся лямбра выкинет исключение
Ручное управление¶
Если для запроса нужна какая-то более сложная логика, либо запросы вне репозитория, можно использовать io.r2dbc.spi.Connection
:
@Component
public final class SomeService {
private final EntityRepository repository;
public SomeService(EntityRepository repository) {
this.repository = repository;
}
public Mono<List<Entity>> saveAll(Entity one, Entity two) {
return repository.getVertxConnectionFactory().inTx(connection -> {
// do some work
});
}
}
Сигнатуры¶
Доступные сигнатуры для методов репозитория из коробки:
Под T
подразумевается тип возвращаемого значения, либо List<T>
, либо Void
, либо UpdateCount
.
T myMethod()
@Nullable T myMethod()
Optional<T> myMethod()
Mono<T> myMethod()
Project Reactor (надо подключить зависимость)Flux<T> myMethod()
Project Reactor (надо подключить зависимость)
Под T
подразумевается тип возвращаемого значения, либо T?
, либо List<T>
, либо Unit
, либо UpdateCount
.
myMethod(): T
suspend myMethod(): T
Kotlin Coroutine (надо подключить зависимость какimplementation
)myMethod(): Flow<T>
Kotlin Coroutine (надо подключить зависимость какimplementation
)