Introducción: Por qué Kotlin y las bases de datos son la pareja ideal
Kotlin es un lenguaje moderno de tipado estático que funciona sobre la JVM. Gracias a su sintaxis concisa, seguridad nula (null safety) y compatibilidad total con Java, Kotlin se ha convertido en uno de los lenguajes de más rápido crecimiento para el desarrollo backend. En este artículo analizaremos cómo conectarse y realizar operaciones CRUD con dos SGBD populares: la relacional PostgreSQL y la orientada a documentos MongoDB.
Veremos dos enfoques principales: el uso de la biblioteca Exposed para SQL y el framework KMongo para trabajar con MongoDB. Todos los ejemplos de código están escritos en Kotlin puro y listos para ejecutarse.
1. Trabajo con PostgreSQL a través de la biblioteca Exposed
1.1. Configuración de dependencias
Para empezar, agregue las siguientes dependencias al archivo build.gradle.kts:
dependencies { implementation("org.jetbrains.exposed:exposed-core:0.44.0") implementation("org.jetbrains.exposed:exposed-dao:0.44.0") implementation("org.jetbrains.exposed:exposed-jdbc:0.44.0") implementation("org.postgresql:postgresql:42.6.0") implementation("com.zaxxer:HikariCP:5.0.1")}HikariCP es un pool de conexiones de alto rendimiento que utilizaremos para gestionar las conexiones a la BD.
1.2. Conexión a la base de datos
Crearemos un objeto para gestionar la conexión:
import com.zaxxer.hikari.HikariConfigimport com.zaxxer.hikari.HikariDataSourceimport org.jetbrains.exposed.sql.Database
object DatabaseFactory { fun init() { val config = HikariConfig().apply { driverClassName = "org.postgresql.Driver" jdbcUrl = "jdbc:postgresql://localhost:5432/my_db" username = "user" password = "password" maximumPoolSize = 10 isAutoCommit = false }
val dataSource = HikariDataSource(config) Database.connect(dataSource) }}1.3. Definición de tablas y operaciones CRUD
Exposed utiliza un estilo DSL para describir tablas. Definamos una tabla simple de usuarios:
import org.jetbrains.exposed.sql.Tableimport org.jetbrains.exposed.sql.*import org.jetbrains.exposed.sql.transactions.transaction
object Users : Table() { val id = integer("id").autoIncrement() val name = varchar("name", 100) val email = varchar("email", 255).uniqueIndex()
override val primaryKey = PrimaryKey(id)}
// Inserción de datosfun insertUser(name: String, email: String) { transaction { Users.insert { it[Users.name] = name it[Users.email] = email } }}
// Lectura de todos los usuariosfun getAllUsers(): List<ResultRow> { return transaction { Users.selectAll().toList() }}
// Actualización de emailfun updateUserEmail(id: Int, newEmail: String) { transaction { Users.update({ Users.id eq id }) { it[email] = newEmail } }}
// Eliminación de usuariofun deleteUser(id: Int) { transaction { Users.deleteWhere { Users.id eq id } }}1.4. Características de Exposed
- Transacciones: Todas las operaciones se ejecutan dentro del bloque
transaction. - Seguridad de tipos: Los errores en las consultas SQL se detectan en tiempo de compilación.
- Migraciones: Exposed soporta la creación automática de tablas mediante
SchemaUtils.create(Users).
2. Trabajo con MongoDB a través de KMongo
2.1. Configuración de dependencias
Agregue a build.gradle.kts:
dependencies { implementation("org.litote.kmongo:kmongo-coroutine:4.9.0") implementation("org.litote.kmongo:kmongo-id:4.9.0")}<