Saltar a contenido

9.1.-Acceso programático a BBDD

9.1. Acceso programático a bases de datos

Resumen

Este primer punto sitúa el problema que resuelve el acceso a bases de datos desde código. Antes de escribir JDBC, necesitamos entender por qué una aplicación necesita persistir información, qué aporta un SGBDR relacional y qué opciones tiene Kotlin para comunicarse con una base de datos.

Una aplicación útil rara vez trabaja solo con datos temporales en memoria. En cuanto necesita recordar usuarios, pedidos, productos, reservas, incidencias o cualquier otra información entre ejecuciones, aparece la necesidad de persistencia.

Las bases de datos resuelven ese problema: permiten guardar información de forma organizada, recuperarla cuando hace falta y compartirla entre distintas partes de una aplicación o entre varias personas usuarias.

La normativa del módulo de Programación indica que el alumnado debe ser capaz de gestionar información almacenada en bases de datos manteniendo la integridad y consistencia de los 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.
CE c Se ha escrito código para almacenar información en bases de datos.
CE d Se han creado programas para recuperar y mostrar información almacenada en bases de datos.
CE e Se han efectuado borrados y modificaciones sobre la información almacenada.
CE f Se han creado aplicaciones que muestren la información almacenada en bases de datos.
CE g Se han creado aplicaciones para gestionar la información presente en bases de datos.

1. Qué debe aprender el alumnado

Al terminar la unidad deberías poder explicar y aplicar estas ideas:

  • Una base de datos permite persistir información de forma organizada, compartida y segura.
  • Una aplicación Kotlin puede acceder a una base de datos relacional mediante JDBC o mediante capas de abstracción superiores.
  • La integridad de los datos depende tanto del diseño de la base de datos como del código que ejecuta conexiones, consultas y transacciones.
  • Las aplicaciones mantenibles separan la lógica de negocio de la lógica de acceso a datos.

2. Bases de datos y persistencia

Una base de datos es un conjunto organizado de información que se almacena y se gestiona en un sistema informático. Su finalidad es permitir que los datos se puedan guardar, recuperar, relacionar, actualizar y proteger de forma eficiente.

Dicho de forma sencilla: si una aplicación necesita conservar información cuando se cierra, compartirla con otros procesos o consultarla de forma flexible, necesita algún mecanismo de persistencia.

Las bases de datos son importantes en el desarrollo de software porque permiten:

  • Gestionar grandes volúmenes de información sin cargarlo todo en memoria.
  • Compartir datos entre varias personas usuarias o servicios.
  • Consultar información mediante criterios, filtros, ordenaciones y agregaciones.
  • Mantener reglas de integridad, como claves primarias, claves foráneas o restricciones de unicidad.
  • Separar la lógica de la aplicación del almacenamiento físico de los datos.

Ejemplo cotidiano

En una aplicación de inventario, los productos, precios, existencias y ventas no pueden depender de una lista en memoria. Deben almacenarse en una base de datos para seguir existiendo al cerrar la aplicación, consultarse desde varios equipos y mantener reglas como "no puede haber dos productos con el mismo código".

Para aterrizarlo, imagina que una tienda guarda sus productos en una colección de Kotlin:

data class Producto(val codigo: String, val nombre: String, val stock: Int)

val productos = mutableListOf(
    Producto("P001", "Teclado", 12),
    Producto("P002", "Ratón", 20)
)

Este código permite trabajar con productos mientras el programa está en ejecución, pero tiene una limitación clara: si la aplicación se cierra, esa lista se pierde salvo que se guarde en algún soporte persistente.

Además, si dos personas modifican el stock al mismo tiempo desde equipos distintos, una lista local no ofrece por sí misma control de concurrencia, permisos ni reglas de integridad.

En una base de datos, esos mismos datos podrían representarse en una tabla:

CREATE TABLE productos (
    codigo VARCHAR(10) PRIMARY KEY,
    nombre VARCHAR(100) NOT NULL,
    stock INT NOT NULL CHECK (stock >= 0)
);

Lectura del ejemplo:

  • codigo identifica de forma única cada producto.
  • nombre no puede quedar vacío porque tiene NOT NULL.
  • stock no puede ser negativo porque tiene una restricción CHECK.
  • Parte de la calidad de los datos se protege desde la base de datos, no solo desde Kotlin.

3. Bases de datos relacionales y SGBDR

Un sistema gestor de bases de datos relacional o SGBDR es el software que permite crear, consultar y mantener una base de datos relacional. También es habitual encontrar la sigla inglesa RDBMS.

En una base de datos relacional, la información se organiza en tablas. Cada tabla contiene filas, que representan registros, y columnas, que representan campos con un tipo de dato.

Base de datos relacional

Una base de datos relacional organiza la información en tablas relacionadas entre sí. Cada tabla tiene columnas con tipos definidos y filas que representan registros concretos.

Las características principales de un SGBDR son:

  • Estructura basada en tablas: los datos se guardan en filas y columnas.
  • Relaciones entre tablas: las claves primarias y foráneas vinculan información de forma coherente.
  • Consultas SQL: el lenguaje SQL permite buscar, filtrar, ordenar, agrupar y modificar información.
  • Integridad de los datos: las restricciones evitan estados incoherentes.
  • Concurrencia: varios clientes pueden acceder a la misma información mientras el gestor controla bloqueos y transacciones.

Un ejemplo sencillo de relación entre tablas sería el siguiente:

CREATE TABLE usuarios (
    id INT PRIMARY KEY,
    nombre VARCHAR(100) NOT NULL,
    email VARCHAR(150) UNIQUE NOT NULL
);

CREATE TABLE pedidos (
    id INT PRIMARY KEY,
    usuario_id INT NOT NULL,
    fecha DATE NOT NULL,
    FOREIGN KEY (usuario_id) REFERENCES usuarios(id)
);

La tabla usuarios guarda los datos de cada persona usuaria. La tabla pedidos guarda pedidos y utiliza usuario_id como clave foránea para indicar a qué usuario pertenece cada pedido.

Lectura del ejemplo

La clave primaria identifica cada fila dentro de su tabla. La clave foránea crea una relación controlada entre tablas. Esta relación no es solo descriptiva: el SGBDR la puede comprobar y rechazar operaciones que rompan la integridad.

El siguiente esquema resume el recorrido habitual entre una aplicación y una base de datos:

flowchart LR
    A[Aplicación Kotlin] --> B[Capa de acceso a datos]
    B --> C[JDBC u otra abstracción]
    C --> D[Driver JDBC]
    D --> E[SGBDR]
    E --> F[(Base de datos relacional)]

4. Kotlin y acceso a bases de datos

Kotlin se ejecuta sobre la JVM, por lo que puede utilizar directamente las bibliotecas del ecosistema Java. Esto permite trabajar con JDBC, que es la API estándar de Java para conectarse a bases de datos relacionales.

En la práctica, Kotlin aporta una sintaxis más concisa, null-safety y facilidad para modelar datos con data class, pero el acceso de bajo nivel se realiza mediante clases de java.sql, como Connection, PreparedStatement, ResultSet o SQLException.

Un modelo sencillo para representar una fila de una tabla de usuarios podría ser:

data class Usuario(
    val id: Int,
    val nombre: String,
    val email: String
)

Esta clase no es una tabla por sí misma. Es una representación en Kotlin de los datos que queremos insertar, recuperar o mostrar.

Conviene distinguir bien estos dos mundos:

  • En la base de datos, una fila de usuarios contiene valores almacenados.
  • En Kotlin, un objeto Usuario contiene valores ya cargados en memoria.
  • El acceso a datos se encarga de transformar filas en objetos y objetos en filas.

5. Métodos de acceso a bases de datos relacionales

Existen varias formas de acceder a una base de datos desde una aplicación. No todas tienen el mismo nivel de abstracción ni sirven igual para todos los proyectos.

5.1. JDBC

JDBC significa Java Database Connectivity. Es una API estándar que permite abrir conexiones, enviar sentencias SQL y recibir resultados desde una base de datos relacional.

JDBC es especialmente útil para aprender los fundamentos porque muestra el flujo real: conexión, sentencia, parámetros, resultados, errores y cierre de recursos.

5.2. ORM

Un ORM (Object-Relational Mapping) es una herramienta que relaciona objetos de la aplicación con tablas de la base de datos. En lugar de escribir todo el SQL manualmente, se trabaja con clases, objetos y métodos.

Ejemplos conocidos son Hibernate en Java o Exposed en Kotlin.

5.3. JPA

JPA (Java Persistence API) es una especificación estándar de Java para gestionar persistencia. No es una implementación concreta: define cómo debe comportarse una API de persistencia.

Hibernate, por ejemplo, puede actuar como implementación de JPA.

5.4. Spring Data

Spring Data es un proyecto del ecosistema Spring que proporciona abstracciones de acceso a datos. Permite crear repositorios y reducir mucho el código necesario para operaciones habituales.

Cómo elegir

Para aprender, conviene empezar con JDBC porque muestra el mecanismo real de conexión, consulta y resultado. Para proyectos grandes, ORM, JPA o Spring Data pueden reducir código repetitivo, pero no sustituyen la necesidad de entender SQL y el funcionamiento de la base de datos.

La siguiente tabla resume una decisión práctica:

Situación Opción razonable Motivo
Aprender cómo se conecta y ejecuta SQL JDBC Muestra el flujo real de bajo nivel.
Proyecto pequeño con pocas consultas JDBC Evita añadir capas innecesarias.
Dominio con muchas entidades relacionadas ORM/JPA Reduce mapeo repetitivo entre objetos y tablas.
Aplicación Spring Boot empresarial Spring Data Integra repositorios, transacciones y configuración.
Consulta SQL muy específica y optimizada JDBC o SQL nativo Permite controlar exactamente la consulta.

6. Cierre del punto

Este punto no pretende que memorices llamadas concretas de JDBC. Su objetivo es dejar clara la línea argumental de la unidad:

  1. Las aplicaciones necesitan persistencia.
  2. Las bases de datos relacionales organizan y protegen la información.
  3. Kotlin puede comunicarse con ellas gracias a JDBC y al ecosistema JVM.
  4. Las capas superiores simplifican trabajo, pero no eliminan la necesidad de comprender conexiones, SQL, transacciones y errores.

En los siguientes puntos entraremos ya en el código: primero con la estructura básica de JDBC, después con sentencias y resultados, y finalmente con aplicaciones CRUD organizadas mediante patrones.

Fuentes y referencias

Presentación