escuela técnica superior de ingeniería informática Diseño de la capa de datos. Acceso a datos con JDBC Departamento de Lenguajes y Sistemas Informáticos Ingeniería del Software II Índice • Introducción • JDBC • • • • Cargar/Descargar el driver Obtener/liberar conexiones Lanzar consultas Tratamiento de las excepciones Introducción • Problema: • ¿Cómo separamos la lógica de negocio del acceso a los datos? • Solución: • Utilizaremos el patrón DAO (“Core J2EE Patterns” ) para desacoplar el acceso a datos de la lógica de negocio. http://java.sun.com/blueprints/corej2eepatterns/Patterns/DataAccessObject.html • Usaremos JDBC para acceder al SGBD Capa de acceso a datos Lógica de negocio Capa de datos (DAO) MySQL Connector/J (Driver JDBC) MySQL • Herramientas: • MySQL • MySQL Connector/J (driver tipo 4 para MySQL) Índice • Introducción • JDBC • • • • Cargar/Descargar el driver Obtener/liberar conexiones Lanzar consultas Tratamiento de las excepciones Introducción • JDBC es un API (java.sql.*) proporcionada por Sun para lanzar sentencias SQL a bases de datos relacionales (estándar ANSI SQL-2) • Los desarrolladores de SGBD proporcionan la implementación de esa interfaz (Drivers) Arquitectura • Tipo 1: (JDBC-ODBC Bridge) delegan el acceso a datos a una API ODBC • Tipo 2: Usan código nativo para el acceso a datos y proveen un envoltorio de clases java para las llamadas al driver. Es por tanto específico para una plataforma • • Tipo 3: Driver 100% Java / Protocolo nativo. Se comunica con el SGBD utilizando el protocolo de red nativo del servidor Tipo 4: Driver 100% Java / Protocolo independiente. Hace las peticiones de datos a un intermediario en un protocolo de red independiente del SGBD API JDBC Driver Manager JDBC Driver JDBC DBMS Bridge JDBC/ODBC Driver ODBC DBMS Modo de trabajo en JDBC Cargar driver Obtener conexión Obtener conexión Crear sentencia JDBC Lanzar consulta Lanzar consulta Ejecutar sentencia Tratar resultado Cerrar conexión Cerrar conexión Descargar driver Liberar recursos JDBC • Necesitaré: • Alguien que represente a un gestor de drivers: DriverManager • Alguien que represente a las conexiones: Connection • Alguien que represente a las sentencias: PreparedStatment • Alguien que represente a los resultados: ResultSet Índice • Introducción • JDBC • • • • Cargar/Descargar el driver Obtener/liberar conexiones Lanzar consultas Tratamiento de las excepciones Cargar driver Obtener conexión Obtener conexión Lanzar consulta Lanzar consulta Cerrar conexión Cerrar conexión Descargar driver Cargar/Descargar el driver • Cargar el driver: Class +static forName(): Class +newInstance(): Object DriverManager +static registerDriver(dbDriver: Driver) +static deregisterDriver(dbDriver: Driver) +static getConnection(dBUri: String, username: String, password: String): Connection Cargar/Descargar el driver • Cargar el driver: Driver dBDriver = (Driver) Class.forName(driverName) .newInstance(); DriverManager.registerDriver(dBDriver); • Descargar el driver: DriverManager.deregisterDriver(dBDriver); • Ejemplos de nombres de driver: • com.microsoft.jdbc.sqlserver.SQLServerDriver (SQLServer) • com.mysql.jdbc.Driver (MySQL Connector/J) Índice • Introducción • JDBC • • • • Cargar/Descargar el driver Obtener/liberar conexiones Lanzar consultas Tratamiento de las excepciones • Ejemplos Identificación del SGBD • Se usa una URI para identificar al DBMS jdbc:mysql://127.0.0.1:3306/POS • Transporte: jdbc • Tipo de base de datos: mysql • Nombre del servidor: 127.0.0.1 • Puerto: 3306 • Base de datos: POS Obtener/liberar conexiones <<interface>> Connection +close() +prepareStatement(String s): PreparedStatement • Una conexión con la base de datos se establece usando un driver ya registrado: Connection conn = DriverManager.getConnection(dBUri, username, password); • Liberar conexión: conn.close(); Índice • Introducción • JDBC • • • • Cargar/Descargar el driver Obtener/liberar conexiones Lanzar consultas Tratamiento de las excepciones Cargar driver Obtener conexión Obtener conexión Crear sentencia JDBC Lanzar consulta Lanzar consulta Ejecutar sentencia Tratar resultado Cerrar conexión Cerrar conexión Descargar driver Liberar recursos Lanzar consultas Crear sentencia JDBC Ejecutar sentencia Tratar resultado Liberar recursos Crear una sentencia JDBC <<interface>> Connection Crear sentencia JDBC Ejecutar sentencia Tratar resultado Liberar recursos +close() +prepareStatement(String s): PreparedStatement <<interface>> PreparedStatement +setBoolean(x: int, y: boolean) +setByte(x: int, y: byte) +setDate(x: int, y: Date) +setDouble(x: int, y: double) +setString(x: int, y: String) +executeQuery(): ResultSet +executeUpdate(): int +execute(): boolean Interfaces proporcionadas por JDBC • Statement • Para la ejecución de sentencias SQL estáticas en tiempo de ejecución • PreparedStatement • Para la ejecución de sentencias SQL, se precompilan (más rápidas) y aceptan parámetros de entrada en tiempo de ejecución • CallableStatement • Para la ejecución de procedimientos almacenados en la base de datos PreparedStatement • Se crean usando el método prepareStatement de una conexión PreparedStatement con.prepareStatement(String s) • El parámetro s hace referencia a la consulta SQL, en la que pueden aparecer parámetros String sql = "DELETE FROM Customer WHERE (CUSTOMERID = ?)"; • De existir parámetros, usamos los métodos setXXX(x,y) para darles valor (x identifica al parámetro, y al valor que toma) Métodos setXXX(x,y) Método de PreparedStatement Tipo del valor y setBoolean(x,y) boolean setByte(x,y) byte setDate(x,y) Date setDouble(x,y) double setFloat(x,y) float setInt(x,y) int setLong(x,y) long setString(x,y) String setTime(x,y) Time setTimeStamp(x,y) TimeStamp setObject(x,y) Object … … Ejemplos PreparedStatement stmt = null; String sql = "DELETE FROM Customer WHERE (CUSTOMERID = ? ) "; stmt = conn.prepareStatement(sql); //conn es una conexión válida stmt.setString(1, customerID); PreparedStatement stmt = null; String sql = "SELECT * FROM Customer"; stmt = conn.prepareStatement(sql); //conn es una conexión válida PreparedStatement stmt = null; String sql = "INSERT INTO CUSTOMER (OID, CUSTOMERID, NAME, SURNAME)”+ “ VALUES (?, ?, ?, ?)"; stmt = conn.prepareStatement(sql); stmt.setString(1, “33423”); stmt.setString(2, “Customer 1”); stmt.setString(3, “Name 1”); stmt.setString(4, “Name 2”); Ejecución de sentencias Crear sentencia JDBC Ejecutar sentencia Tratar resultado Liberar recursos <<interface>> PreparedStatement +setBoolean(x: int, y: boolean) +setByte(x: int, y: byte) +setDate(x: int, y: Date) +setDouble(x: int, y: double) +setString(x: int, y: String) +executeQuery(): ResultSet +executeUpdate(): int +execute(): boolean Métodos de PreparedStatement • ResultSet executeQuery() • Ejecuta una sentencia de tipo “SELECT”, devuelve un objeto ResultSet con los resultados de la consulta • int executeUpdate() • Ejecuta una sentencia de tipo “INSERT”, “UPDATE” o “DELETE”. Devuelve el número de registros insertados/actualizados/borrados • boolean execute() • Para la ejecución de procedimientos almacenados en la base de datos, … Tratar el resultado Crear sentencia JDBC <<interface>> Resulset Ejecutar sentencia Tratar resultado Liberar recursos +next(): boolean +first(): boolean +getXXX(s: String): XXX +close() Tratar el resultado • El resultado de ejecutar un SELECT se devuelve en un objeto de tipo ResulSet • Métodos de interés: • next(): para iterar por las filas del ResulSet (la primera llamada nos posiciona en la primera fila de resultados) • first(): para ir al principio del ResulSet • getXXX(s): devuelve el valor, dentro de una fila, especificado por s (índice o nombre de columna) Métodos getXXX(s) Método de ResulSet Tipo Java getBoolean(s) boolean getByte(s) byte getDate(s) Date getDouble(s) double getFloat(s) float getInt(s) int getLong(s) long getString(s) String getTime(s) Time getTimeStamp(s) TimeStamp getObject(s) Object … … Liberar recursos <<interface>> PreparedStatement Crear sentencia JDBC Ejecutar sentencia +setBoolean(x: int, y: boolean) +setByte(x: int, y: byte) +setDate(x: int, y: Date) +setDouble(x: int, y: double) +setString(x: int, y: String) +executeQuery(): ResultSet +executeUpdate(): int +execute(): boolean +close() Tratar resultado <<interface>> Resulset Liberar recursos +next(): boolean +first(): boolean +getXXX(s: String): XXX +close() Liberar recursos • Liberar los objetos usados del tipo: • PreparedStatement • ResulSet (si hemos lanzado un SELECT) PreparedStatement stmt = null; ResulSet result = null; ... stmt.close(); result.close(); Ejemplos de consultas <<Class Model>> Customer -customerID -name -surname <<Physical Data Model>> Customer OID = <<PK>> customerID name surname CREATE TABLE CUSTOMER ( OID varchar(50) NOT NULL, CUSTOMERID varchar(50) NOT NULL, NAME varchar(50) NOT NULL, SURNAME varchar(50) NOT NULL, PRIMARY KEY(OID)); Ejemplo de Select (1) PreparedStatement stmt = null; ResultSet result = null; Customer c = null; String sql = "SELECT * FROM CUSTOMER WHERE (CUSTOMERID = ? ) "; stmt = conn.prepareStatement(sql); //conn es una conexión válida stmt.setString(1, customerID); result = stmt.executeQuery(); result.next(); c = new Customer(); c.setCustomerID(result.getString("CUSTOMERID")); c.setName(result.getString("NAME")); c.setSurname(result.getString("SURNAME")); result.close(); stmt.close(); Ejemplo de Select (2) PreparedStatement stmt = null; List searchResults = new LinkedList(); ResultSet result = null; String sql = "SELECT * FROM Customer"; stmt = conn.prepareStatement(sql); //conn es una conexión válida stmt.executeQuery(); result = stmt.executeQuery(); while (result.next()) { Customer temp = new Customer(); temp.setCustomerID(result.getString("customerID")); temp.setName(result.getString("name")); temp.setSurname(result.getString("surname")); searchResults.add(temp); } result.close(); stmt.close(); Ejemplo de Insert PreparedStatement stmt = null; String oid = UIDGenerator.getInstance().getKey(); String sql = "INSERT INTO CUSTOMER (OID, CUSTOMERID, NAME, SURNAME)”+ “ VALUES (?, ?, ?, ?)"; stmt = conn.prepareStatement(sql); stmt.setString(1, stmt.setString(2, stmt.setString(3, stmt.setString(4, oid); c.getCustomerID()); c.getName()); c.getSurname()); stmt.executeUpdate(); stmt.close(); Ejemplo de Delete String sql = "DELETE FROM Customer WHERE (CUSTOMERID = ? ) "; PreparedStatement stmt = null; stmt = conn.prepareStatement(sql); //conn es una conexión válida stmt.setString(1, customerID); stmt.executeUpdate(); stmt.close(); Índice • Introducción • JDBC • • • • Cargar/Descargar el driver Obtener/liberar conexiones Lanzar consultas Tratamiento de las excepciones Tratamiento de excepciones • Se pueden producir una excepción: • Al cargar el driver (Class.forName): • InstantiationException • IllegalAccessException • ClassNotFoundException • Al utilizar los métodos definidos en las interfaces que proporciona JDBC (JDBC usa excepciones para el tratamiento de los errores) : • SQLException Cargar driver ... try { // Aquí va el código para cargar el driver } catch(Exception e) { System.err.println(e.getMessage()); } ... Métodos jdbc Captura de las excepciones ... try { // Aquí va el código que podría generar la excepción. } catch(SQLException e) { // Descripción del error System.out.println("Message: " + e.getMessage()); // identificación del error System.out.println("SQLState: " + e.getSQLState()); // Código de error del vendedor System.out.println("ErrorCode: " + e.getErrorCode()); } ... Métodos JDBC (liberación recursos) • A veces es necesario liberar recursos, se produzca o no una excepción ... PreparedStatement stmt; ResultSet result; Connection conn; ... try { // Aquí va el código que podría generar la excepción. // y que hace uso de stmt, result y conn } catch (SQLException e) { System.out.println("Message: " + e.getMessage()); System.out.println("SQLState: " + e.getSQLState()); System.out.println("ErrorCode: " + e.getErrorCode()); } finally { conn.close(); if (result != null) {result.close();} if (stmt != null) {stmt.close();} } ... ¡Gracias! • ¿Podemos mejorar esta lección? Mándanos un email a benavides@us.es Visita la web: www.lsi.us.es