Saltar a contenido

9.2.-Introducción a JDBC

9.2. Introducción a JDBC

Resumen

En este punto empezamos a escribir código. El objetivo es entender qué piezas necesita una aplicación Kotlin para abrir una conexión JDBC: dependencia del driver, URL, credenciales, Connection, cierre con use y diferencia entre DriverManager y DataSource.

JDBC es una API de bajo nivel. Esto significa que nos obliga a controlar detalles que otras herramientas esconden: conexión, sentencias, resultados, errores y cierre de recursos.

Precisamente por eso es una buena forma de aprender qué ocurre realmente cuando una aplicación consulta una base de datos.

Código Descripción
RA9 Gestiona información almacenada en bases de datos manteniendo la integridad y consistencia de los datos.
CE a Se han identificado las características y métodos de acceso a sistemas gestores de bases de datos.
CE b Se han programado conexiones con bases de datos.

1. Qué es JDBC

JDBC significa Java Database Connectivity. Es una API estándar del mundo Java que permite interactuar con bases de datos relacionales.

Desde Kotlin podemos usar JDBC porque Kotlin se ejecuta sobre la JVM y puede utilizar bibliotecas Java.

Un flujo básico con JDBC tiene esta forma:

Aplicación Kotlin
    -> API JDBC
    -> Driver del SGBDR
    -> Base de datos

Idea clave

JDBC define una forma común de trabajar con bases de datos, pero cada gestor necesita su driver: PostgreSQL, MySQL, MariaDB, H2, SQLite, etc.

Kotlin y JDBC

Kotlin puede usar JDBC gracias a su interoperabilidad con Java en la JVM.

2. Preparar el proyecto

Para que JDBC pueda comunicarse con una base de datos necesitamos añadir el driver correspondiente.

En los ejemplos de la unidad se usa H2 porque permite practicar sin instalar un servidor externo. En Gradle Kotlin DSL se puede añadir así:

dependencies {
    implementation("com.h2database:h2:2.2.224")
}

Lectura del ejemplo:

  • implementation(...) añade una dependencia al proyecto.
  • com.h2database:h2 identifica el driver JDBC de H2.
  • Si se usa PostgreSQL, MySQL u otro gestor, la dependencia será distinta.
  • Sin driver, JDBC no puede comunicarse con el SGBDR elegido.

Driver correcto

Si el driver no está en el classpath, la aplicación no podrá abrir la conexión aunque la URL, el usuario y la contraseña sean correctos.

3. URL JDBC

Una URL JDBC indica a qué base de datos queremos conectarnos. Para H2 en fichero puede tener esta forma:

val jdbcUrl = "jdbc:h2:./data/tienda"

La URL se puede leer así:

Parte Valor Significado
Protocolo jdbc:h2 Usa JDBC con H2.
Ruta ./data/tienda Fichero donde H2 guarda la base de datos.

En PostgreSQL, la URL tendría un formato distinto:

val jdbcUrl = "jdbc:postgresql://localhost:5432/tienda"

Formato de URL JDBC

Formato habitual de una URL JDBC: gestor, servidor, puerto y base de datos.

4. Abrir una conexión

La clase Connection representa una conexión activa con la base de datos. Para abrirla de forma sencilla podemos usar DriverManager.getConnection.

import java.sql.DriverManager
import java.sql.SQLException

fun main() {
    val jdbcUrl = "jdbc:h2:./data/tienda"
    val username = "sa"
    val password = ""

    try {
        DriverManager.getConnection(jdbcUrl, username, password).use { connection ->
            println("Conexión válida: ${connection.isValid(2)}")
        }
    } catch (e: SQLException) {
        println("No se ha podido conectar: ${e.message}")
    }
}

Lectura del ejemplo:

  • jdbcUrl indica la base de datos de destino.
  • username y password son las credenciales.
  • getConnection intenta abrir la conexión.
  • use cierra la conexión al terminar el bloque.
  • isValid(2) comprueba si la conexión responde en dos segundos.
  • catch captura errores de JDBC mediante SQLException.

Busca el ejemplo ConexionValida y estúdialo o ejecútalo.

5. Qué puede fallar al conectar

Abrir una conexión es una operación externa al programa: depende del driver, de la ruta o servidor, de credenciales y del estado de la base de datos.

Errores habituales:

  • Driver no añadido al proyecto.
  • URL JDBC mal escrita.
  • Base de datos inexistente o servidor apagado.
  • Usuario o contraseña incorrectos.
  • Permisos insuficientes.
  • Problemas de red en bases de datos remotas.

Separar problemas

Antes de depurar una consulta SQL compleja, comprueba que la conexión se abre correctamente. Si la conexión falla, el problema todavía no está en el SELECT, el INSERT ni el mapeo a objetos.

6. DriverManager y DataSource

DriverManager es útil para ejemplos pequeños porque permite abrir una conexión de forma directa. En aplicaciones reales es habitual trabajar con DataSource.

Un DataSource representa una fuente de conexiones. Puede estar respaldado por un pool, como HikariCP, que reutiliza conexiones para no abrir una conexión física nueva en cada operación.

Dependencia básica de HikariCP:

dependencies {
    implementation("com.zaxxer:HikariCP:5.1.0")
}

Configuración mínima:

import com.zaxxer.hikari.HikariDataSource

fun crearDataSource(): HikariDataSource =
    HikariDataSource().apply {
        jdbcUrl = "jdbc:h2:./data/tienda"
        username = "sa"
        password = ""
        maximumPoolSize = 10
    }

Lectura del ejemplo:

  • HikariDataSource representa un pool de conexiones.
  • jdbcUrl, username y password configuran el acceso.
  • maximumPoolSize limita el número máximo de conexiones abiertas.
  • El resto del código puede pedir conexiones al DataSource.

Uso básico:

val dataSource = crearDataSource()

dataSource.connection.use { connection ->
    println("Conexión obtenida del pool: ${connection.isValid(2)}")
}

No confundir cerrar con destruir

Al usar un pool, cerrar una conexión normalmente significa devolverla al pool, no destruir la conexión física con el SGBDR.

Busca el ejemplo PoolHikariBasico y estúdialo o ejecútalo.

7. Secuencia mínima de trabajo

Una operación JDBC completa suele seguir esta secuencia:

flowchart TD
    A[Obtener conexión] --> B[Preparar sentencia]
    B --> C[Asignar parámetros si existen]
    C --> D[Ejecutar]
    D --> E[Leer resultados o filas afectadas]
    E --> F[Cerrar recursos]
    F --> G[Tratar errores]

En este punto nos hemos centrado en el primer paso: obtener la conexión. En el siguiente punto profundizaremos en Statement, PreparedStatement y ResultSet.

8. Ideas clave

  • JDBC es la API estándar de la JVM para acceder a bases de datos relacionales.
  • Kotlin puede usar JDBC porque se ejecuta sobre la JVM.
  • Cada SGBDR necesita su driver.
  • La URL JDBC identifica la base de datos de destino.
  • Connection representa una conexión activa.
  • use ayuda a cerrar recursos aunque se produzca una excepción.
  • DataSource es preferible en aplicaciones que necesitan gestionar conexiones de forma más robusta.

Fuentes y referencias

Presentación