Herramientas de usuario

Herramientas del sitio


apuntes:jdbc

Diferencias

Muestra las diferencias entre dos versiones de la página.

Enlace a la vista de comparación

Ambos lados, revisión anteriorRevisión previa
Próxima revisión
Revisión previa
apuntes:jdbc [2018/12/14 19:14] – [Procedimientos almacenados] fernandoapuntes:jdbc [2024/09/16 16:03] (actual) – editor externo 127.0.0.1
Línea 6: Línea 6:
  
 Ya que, como hemos dicho, el driver es lo único que depende exclusivamente del SGBD utilizado, es muy sencillo escribir aplicaciones cuyo código se pueda reutilizar si más adelante tenemos que cambiar de motor de Base de Datos o bien si queremos permitir que dicha aplicación pueda conectarse a más de un SGBD de forma que el usuario no tenga porque comprometerse a un SGBD concreto si la adquiere o quiere ponerla en marcha. Ya que, como hemos dicho, el driver es lo único que depende exclusivamente del SGBD utilizado, es muy sencillo escribir aplicaciones cuyo código se pueda reutilizar si más adelante tenemos que cambiar de motor de Base de Datos o bien si queremos permitir que dicha aplicación pueda conectarse a más de un SGBD de forma que el usuario no tenga porque comprometerse a un SGBD concreto si la adquiere o quiere ponerla en marcha.
 +
 ===== Operaciones básicas con JDBC ===== ===== Operaciones básicas con JDBC =====
  
Línea 80: Línea 81:
 === Conectarse a un SGBD sin seleccionar una bbdd === === Conectarse a un SGBD sin seleccionar una bbdd ===
 Cuando queremos conectarnos a un SGBD para posteriormente seleccionar la base de datos que queremos consultar, podemos hacerlo del siguiente modo: Cuando queremos conectarnos a un SGBD para posteriormente seleccionar la base de datos que queremos consultar, podemos hacerlo del siguiente modo:
 +
 <code java> <code java>
 . . . . . .
-Connection conexion = null;+//Me conecto a MySql sin indicar ninguna tabla
  
-conexion = DriverManager.getConnection("jdbc:mysql://localhost:3306/", +Connection conexion = DriverManager.getConnection("jdbc:mysql://localhost:3306/", 
            "usuario", "password");            "usuario", "password");
  
Línea 90: Línea 92:
 ResultSet catalogo = conexion.getMetaData().getCatalogs(); ResultSet catalogo = conexion.getMetaData().getCatalogs();
  
-//Accedo a las bases de datos que existen en ese SGBD+//Muestro los nombres de las bases de datos que existen en ese SGBD
 while (catalogo.next()) { while (catalogo.next()) {
    System.out.println(catalogo.getString(1));    System.out.println(catalogo.getString(1));
Línea 97: Línea 99:
  
 //Cuando sepa a qué base de datos conectarme //Cuando sepa a qué base de datos conectarme
-conexion.setCatalog("baseDeDatos");+conexion.setCatalog("nombreBaseDeDatos");
  
 </code> </code>
  
-==== Insertar datos ====+===== Consultas sobre la base de datos====
 +Para ejecutar una consulta (INSERT, UPDATE, DELETE o SELECT) emplearemos un objeto de tipo ''PreparedStatement''. Este objeto será creado mediante el método ''prepareStatement(consulta)'' de la clase ''Connection'', que recibe un String con la consulta SQL. Además, el objeto PreparedStatement se puede crear a partir de una consulta parametrizada ('?'). Podemos dar valor a esos parámetros posteriormente.
  
 +==== Insertar datos en la base de datos ====
 +Ejecutaremos una consulta de tipo INSERT:
 <code java> <code java>
 . . . . . .
Línea 125: Línea 130:
 . . . . . .
 </code> </code>
-==== Modificar datos ====+ 
 +==== Modificar datos de la base de datos====
  
 <code java> <code java>
Línea 151: Línea 157:
 . . . . . .
 </code> </code>
 +
 ==== Eliminar datos ==== ==== Eliminar datos ====
  
Línea 177: Línea 184:
 {{ youtube>Oe6SmYgPPD4 }} {{ youtube>Oe6SmYgPPD4 }}
 \\ \\
-==== Consultas ====+==== Consultas de Seleccion==== 
 + 
 +Una consulta de selección sobre una tabla de la base de datos devuelve un conjunto de datos organizados en filas y columnas (registros). En Java almacenamos esa información mediante un objeto de la clase ''ResultSet'', el cual está formado por filas y columnas. 
 + 
 +Un ''ResultSet'' solo puede recorrerse fila por fila, desde la primera hasta la última en una única dirección deon su método ''next()''. Además, podemos acceder a cualquier columna de cada fila mediante algunos de sus métodos (''getInt()'', ''getString()'', ''getObject()'', etc). Las columnas se numeran empezando en el nº **1**.
  
 <code java> <code java>
Línea 205: Línea 216:
 . . . . . .
 </code> </code>
- 
-Hay que tener en cuenta que el objeto //ResultSet// es el cursor que contiene el resultado de la consulta y, al recorrerlo, podemos acceder a cualquier columna de dicho resultado indicando el número de ésta, siempre teniendo en cuenta que la posición 0 se reserva al número de la fila en el resultado de la consulta. 
  
 También se pueden parametrizar la consulta, tal y como se muestra en el siguiente ejemplo donde se mostrará la información de los productos de un determinado precio. También se pueden parametrizar la consulta, tal y como se muestra en el siguiente ejemplo donde se mostrará la información de los productos de un determinado precio.
Línea 239: Línea 248:
 </code> </code>
  
-En el caso de las funciones agregadas, podremos tener en cuenta que sólo van a devolver un valor, por lo que no será necesario preparar el código para recorrer el cursor. Podremos acceder directamente a la primera fila del //ResultSet// y mostrar el resultado, tal y como se muestra en el siguiente ejemplo:+En el caso de las funciones agregadas de SQL (COUNT(), AVG(), MAX(), SUM(), MIN(), etc), podremos tener en cuenta que sólo van a devolver un valor, por lo que no será necesario preparar el código para recorrer el cursor. Podremos acceder directamente a la primera fila del //ResultSet// y mostrar el resultado, tal y como se muestra en el siguiente ejemplo:
  
 <code java> <code java>
Línea 286: Línea 295:
  
 ==== Obtener las columnas de una consulta Select ==== ==== Obtener las columnas de una consulta Select ====
-Si en algún caso al realizar una consulta no sabemos cuántas columnas nos va a devolver, podemos usar el método ''getMetaData()'' que devuelve un objeto del tipo ResultSetMetaData.+Si en algún caso al realizar una consulta no sabemos cuántas columnas nos va a devolver, podemos usar el método ''getMetaData()'' que devuelve un objeto del tipo ''ResultSetMetaData''.
  
 Existen dos formas de usar dicho método. Se puede invocar desde un objeto de tipo ResultSet obtenido de la ejecución de una consulta:  Existen dos formas de usar dicho método. Se puede invocar desde un objeto de tipo ResultSet obtenido de la ejecución de una consulta: 
Línea 302: Línea 311:
 <code java> <code java>
 ... ...
-PreparedStatement sentencia = conexión.preparedStatement(consulta);+PreparedStatement sentencia = conexion.preparedStatement(consulta);
  
 ResultSetMetaData resultadoMetaData = sentencia.getMetaData(); ResultSetMetaData resultadoMetaData = sentencia.getMetaData();
 int numeroColumnas = resultadoMetaData.getColumnCount(); int numeroColumnas = resultadoMetaData.getColumnCount();
 </code> </code>
-===== Transacciones ===== 
  
-En el ámbito de las Bases de Datos, una transacción es cualquier conjunto de sentencias SQL que se ejecutan como si de una sola se tratara. La idea principal es poder ejecutar varias sentencias, que están relacionadas de alguna manera, de forma que si cualquiera de ellas fallara o produjera un error, no se ejecutara ninguna más e incluso se deshicieran todos los cambios que hayan podido efectuar las que ya se habían ejecutado dentro de la misma transacción. 
- 
-Para ello, tendremos que incorporar tres nuevas instrucciones a las que ya veníamos utilizando hasta ahora. Una instrucción para indicar que comienza una transacción (''conexion.setAutoCommit(false)''), otra para indicar cuando termina (''conexion.commit()'') y otra para indicar que la transacción actual debe abortarse y todos los cambios hasta el momento deben ser restaurados al estado anterior (''conexion.rollback()''). 
- 
-<code java> 
-. . . 
-String nombreProducto = . . .; 
-float precioProducto = . . .; 
-int idCategoria = . . .; 
-// El id del producto que vamos a registrar aún no se conoce 
- 
-String sqlAltaProducto = "INSERT INTO productos (nombre, precio) VALUES (?, ?)"; 
-String sqlRelacionProducto =  
-       "INSERT INTO producto_categoria(id_producto, id_categoria) " + 
-       "VALUES (?, ?)"; 
-                               
-try { 
-  //Inicia transacción 
-  conextion.setAutoCommit(false); 
-   
-  PreparedStatement sentenciaAltaProducto =  
-                    conexion.prepareStatement(sqlAltaProducto, 
-                    PreparedStatement.RETURNS_GENERATED_KEYS); 
-  sentenciaAltaProducto.setString(1, nombreProducto); 
-  sentenciaAltaProducto.setFloat(2, precioProducto); 
-  sentencia.executeUpdate(); 
-   
-  // Obtiene el id del producto que se acaba de registrar 
-  ResultSet idGenerados = sentenciaAltaProducto.getGeneratedKeys(); 
-  idsGenerados.next(); 
-  int idProducto = idsGenerados.getInt(1); 
-  sentenciaAltaProducto.close(); 
-   
-  PreparedStatement sentenciaRelacionProducto = 
-                    conexion.prepareStatement(sqlRelacionProducto); 
-  sentenciaRelacionProducto.setInt(1, idProducto); 
-  sentenciaRelacionProducto.setInt(2, idCategoria); 
-  sentenciaRelacionProducto.executeUpdate(); 
-   
-  // Valida la transacción 
-  conexion.commit(); 
-} catch (SQLException sqle) { 
-  sqle.printStackTrace(); 
-} finally { 
-  if (sentencia != null) 
-    try { 
-      sentencia.close(); 
-      resultado.close(); 
-    } catch (SQLException sqle) { 
-      sqle.printStackTrace(); 
-    } 
-} 
-. . . 
-</code> 
- 
-{{ youtube>WF0jg2nn9-w }} 
-\\ 
 ===== Procedimientos y funciones almacenadas ===== ===== Procedimientos y funciones almacenadas =====
  
Línea 383: Línea 334:
     SET v_id_polideportivo = (SELECT id FROM polideportivos     SET v_id_polideportivo = (SELECT id FROM polideportivos
                                 WHERE nombre = p_nombre_polideportivo);                                 WHERE nombre = p_nombre_polideportivo);
-    IF v_id_polideportivo NULL THEN+    IF v_id_polideportivo IS NULL THEN
         LEAVE procedimiento;         LEAVE procedimiento;
     END IF;     END IF;
Línea 393: Línea 344:
 END procedimiento; || END procedimiento; ||
 DELIMITER ; DELIMITER ;
 +
 +CALL nueva_pista('4255-GSF', 'tenis', 2.45, 'Las Rozas'); -- LLamo al procedimiento
 </code> </code>
  
Línea 398: Línea 351:
 . . . . . .
 //Método para eliminar todos los productos //Método para eliminar todos los productos
 +
 String sentenciaSql = "call eliminar_todos_los_productos()"; String sentenciaSql = "call eliminar_todos_los_productos()";
 CallableStatement procedimiento = null; CallableStatement procedimiento = null;
Línea 427: Línea 381:
 . . . . . .
 </code> </code>
 +
 ==== Funciones almacenadas ==== ==== Funciones almacenadas ====
  
-En el caso de las funciones almacenadas, para su ejecución seguiremos la misma estructura que hemos visto en el caso de las consultas SQL para el caso concreto de las funciones agregadas, ya que nuestras funciones nos devolverán siempre un solo valor (o null en el caso de que no devuelvan nada).+En el caso de la ejecución de las funciones almacenadas, seguiremos la misma estructura que con las funciones de agregación de SQL (COUNT(), SUM(), AVG()), ya que nuestras funciones nos devolverán siempre un solo valor (o null en el caso de que no devuelvan nada)
 + 
 + 
 +<code sql> 
 + 
 +-- Función que devuelve el número de reservas que ha realizado un usuario determinado 
 + 
 +DELIMITER || 
 +CREATE FUNCTION get_numero_reservas(p_id_usuario INT) 
 +RETURNS INT 
 +BEGIN 
 +    DECLARE cantidad INT; 
 +    DECLARE existe_usuario INT; 
 +  
 +    SET existe_usuario = (SELECT COUNT(*) FROM usuarios 
 +                          WHERE id = p_id_usuario); 
 +    IF existe_usuario = 0 THEN 
 +        -- Si el usuario no existe se devuelve valor de error 
 +        RETURN -1; 
 +    END IF; 
 +  
 +    -- Si todo va bien, se calcula la cantidad y se devuelve 
 +    SET cantidad = (SELECT COUNT(*) FROM reservas R, usuario_reserva UR 
 +        WHERE R.id = UR.id_reserva AND UR.id_usuario = p_id_usuario); 
 +    RETURN cantidad; 
 +  
 +END; || 
 +DELIMITER ; 
 + 
 +SELECT get_numero_reservas(3); -- Muestro la cantidad de reservas del usuario con id = 3 
 +</code> 
 + 
 +Recordamos que como una función solo devuelve un único valor, no es necesario usar un bucle para recorrer el ResultSet. Bastará con quedarnos con la primera fila.
  
 <code java> <code java>
Línea 455: Línea 442:
  
 {{ youtube>10Ypx8Lt2iM }} {{ youtube>10Ypx8Lt2iM }}
 +\\
 +
 +===== Transacciones =====
 +
 +En el ámbito de las Bases de Datos, una transacción es cualquier conjunto de sentencias SQL que se ejecutan como si de una sola se tratara. La idea principal es poder ejecutar varias sentencias, que están relacionadas de alguna manera, de forma que si cualquiera de ellas fallara o produjera un error, no se ejecutara ninguna más e incluso se deshicieran todos los cambios que hayan podido efectuar las que ya se habían ejecutado dentro de la misma transacción.
 +
 +Para ello, tendremos que incorporar tres nuevas instrucciones a las que ya veníamos utilizando hasta ahora. Una instrucción para indicar que comienza una transacción (''conexion.setAutoCommit(false)''), otra para indicar cuando termina (''conexion.commit()'') y otra para indicar que la transacción actual debe abortarse y todos los cambios hasta el momento deben ser restaurados al estado anterior (''conexion.rollback()'').
 +
 +<code java>
 +. . .
 +String nombreProducto = . . .;
 +float precioProducto = . . .;
 +int idCategoria = . . .;
 +// El id del producto que vamos a registrar aún no se conoce
 +
 +String sqlAltaProducto = "INSERT INTO productos (nombre, precio) VALUES (?, ?)";
 +String sqlRelacionProducto = 
 +       "INSERT INTO producto_categoria(id_producto, id_categoria) " +
 +       "VALUES (?, ?)";
 +                              
 +try {
 +  //Inicia transacción
 +  conextion.setAutoCommit(false);
 +  
 +  PreparedStatement sentenciaAltaProducto = 
 +                    conexion.prepareStatement(sqlAltaProducto,
 +                    PreparedStatement.RETURNS_GENERATED_KEYS);
 +  sentenciaAltaProducto.setString(1, nombreProducto);
 +  sentenciaAltaProducto.setFloat(2, precioProducto);
 +  sentencia.executeUpdate();
 +  
 +  // Obtiene el id del producto que se acaba de registrar
 +  ResultSet idGenerados = sentenciaAltaProducto.getGeneratedKeys();
 +  idsGenerados.next();
 +  int idProducto = idsGenerados.getInt(1);
 +  sentenciaAltaProducto.close();
 +  
 +  PreparedStatement sentenciaRelacionProducto =
 +                    conexion.prepareStatement(sqlRelacionProducto);
 +  sentenciaRelacionProducto.setInt(1, idProducto);
 +  sentenciaRelacionProducto.setInt(2, idCategoria);
 +  sentenciaRelacionProducto.executeUpdate();
 +  
 +  // Valida la transacción
 +  conexion.commit();
 +} catch (SQLException sqle) {
 +  sqle.printStackTrace();
 +} finally {
 +  if (sentencia != null)
 +    try {
 +      sentencia.close();
 +      resultado.close();
 +    } catch (SQLException sqle) {
 +      sqle.printStackTrace();
 +    }
 +}
 +. . .
 +</code>
 +
 +{{ youtube>WF0jg2nn9-w }}
 \\ \\
  
apuntes/jdbc.1544814857.txt.gz · Última modificación: 2024/09/16 16:05 (editor externo)