Bases de Datos usando Java : JDBC Ing. César Julio Bustacara Medina JDBC Java permite conectarse a bases de datos usando SQL-92 (Structured Query Language). La gran ventaja de esta utilidad es que una BD. puede migrarse y aún ser vista con el mismo programa Java. Usualmente, una aplicación con acceso a BD. se programa en un lenguaje propietario y sobre un sistema manejador de BD propietario. JDBC La API Java para el manejo de Bases de Datos es JDBC (¿Java DataBase Connectivity?). Este modelo no es una derivación de ODBC (Open DataBase Connectivity) JDBC está escrito en Java ODBC está escrito en C En esencia, la idea es la misma: un programa dialoga con el JDBC driver manager quien a su vez se comunica con un controlador particular. JDBC JDBC es una interface hacia SQL, el lenguaje común de todas las BD relacionales modernas. Las BD de escritorio cuentan con GUIs para manipular directamente los datos pero las BD servidor se controlan a través de SQL. Para conectarse a una BD se debe especificar el nombre de la BD y algunos parámetros adicionales. Capas JDBC • Capa Aplicación (Application Layer) – Conjunto de clases (API) usadas para hacer llamados a la base de datos a través de SQL, obtener y procesar los resultados. • Capa Manejador (Driver Layer) – Conjunto de clases (API) que se encargan de establecer, manejar y terminar la comunicación con un RDBMS (Implementación especifica de un driver) Capas JDBC Driver Layer Application Layer Tipo de Drivers • JDBC-ODBC Bridge (1) – Las llamadas JDBC son enviadas a una librería ODBC. • Librería Nativa (2) – Usa librerías nativas en C (Propias del RDBMS), para trasladar instrucciones JDBC al cliente nativo. • Protocolo de red.(3) – Las llamadas JDBC son trasladadas a un protocolo independiente de RDBMS y enviadas a un servidor intermedio (AppServer) sobre un socket TCP/IP • Protocolo/Librería Nativa 100% java (4) – Las llamadas JDBC son convertidas directamente al protocolo del RDBMS Tipo de Drivers • JDBC-ODBC Bridge (1) – Las llamadas JDBC son enviadas a una librería ODBC. Tipo de Drivers • Librería Nativa (2) – Usa librerías nativas en C (Propias del RDBMS), para trasladar instrucciones JDBC al cliente nativo del RBDMS. Tipo de Drivers • Protocolo de red.(3) – Las llamadas JDBC son trasladadas a un protocolo independiente de RDBMS y enviadas a un servidor intermedio (AppServer) sobre un socket TCP/IP Tipo de Drivers • Protocolo/Librería Nativa 100% java (4) – Las llamadas JDBC son convertidas directamente al protocolo del RDBMS Modelo Two-Tier Cliente/Servidor Aplicación Cliente Aplicación Cliente B.D. Firewall Drivers JDBC • JDBC/OCI • Oracle thin • Servidor de drivers JDBC Drivers JDBC oci : Intranets y para servidores middle-tier. Extranets, es necesario tener instalado el firewall. Convierte sus llamados directamente en Net8. Funciona sobre varios protocolos Modelo usando OCI Aplicación Java Driver JDBC/OCI Aplicación Java Net8 Driver JDBC/OCI B.D. Net8 Firewall Drivers JDBC Thin : • • • • • Funciona para internet No “requiere” driver en el cliente Es 100% Java Funciona solamente sobre TCP/IP No ofrece completa funcionalidad con Net8 Modelo thin Aplicación Java Driver thin Aplicación Java Net8 Net8 Driver thin B.D. Net8 Firewall Instalar el Driver • Para nuestro caso bajar la librería classes12.zip si se esta usando oracle 8.1.5 o superior, de lo contrario usar la librería classes111.zip ubicadas en la página http://technet.oracle.com/software Instalar el Driver • Coloquela en el directorio que desee y adicionelo al classpath path\classes12.zip • Sugerencia: colocarlo en: ...jdk1.3\jre\lib\ext\classes12.zip • adicione el directorio al classpath Verificación import java.sql.*; public class DriverLoader{ public static void main (String arg[]){ try{ DriverManager.registerDriver(new oracle.jdbc.driver.OracleDriver()); } catch(Exception e){ e.printStackTrace(); } } } Verificación • Si hay error se despliega el mensaje Class oracle.jdbc.driver.OracleDriver not found in type declaration DriverManager.registerDriver(new oracle.jdbc.driver.oracleDriver()); ^ Otra forma de registrar el driver Usando el metodo forName de la clase (java.lang). •Cargar y registrar el driver a memoria. – Class.forName(“ clase java del driver”) Ejemplos: Class.forName(“sun.jdbc.odbc.JdbcOdbcDriver” );//Odbc -tipo 1 Class.forName(“oracle.jdbc.driver.OracleDriv er”); //Oracle - Tipo 4 Capa Aplicación • Clases/Interfaces que permiten interactuar con el RDBMS a través de instrucciones SQL (Select, DDL, DML): – Connection – Statement – PreparedStatement – CallableStatement – ResultSet – ResultMetaData • Se agrupan bajo el paquete java.sql.* Capa Aplicación • Connection – Representa una sesión con la conexión a la base de datos – La función principal de connection, es crear objetos tipo Statement (Statement,PreparedStatement, CallableStatement) – Cómo se crea: • Connection conn=DriverManager.getConnection ( url ); • Connection conn=DriverManager.getConnection ( url, user, password ); – Características transaccionales: • conn.setAutocommit(false/true); • conn.rollback(); • conn.commit(); Capa Aplicación • Statement – Es el canal a través del cual se le envían instrucciones SQL a la base de datos y se reciben los resultados. – Las instrucciones SQL puede ser instrucciones DML (Insert, Update, Delete), DDL (Create, Drop) o instrucciones SELECT. – Como se crea: – Statement stmt= conn.createStatement(); – Sobre una conexión se pueden tener n objetos Statement. – Métodos de ejecución: • Ejecución de instrucciones SELECT – ResultSet resultadoSelect = stmt.executeQuery(sql); • Ejecución de instrucciones DML/DDL – int resultadoDML = stmt.executeUpdate(sql); Capa Aplicación • PreparedStatement (Hereda de Statement) – Se usa cuando se llama “n” veces la misma instrucción. – Permite el manejo de parámetros dinámicos – Ventajas técnicas sobre Statement: • Si se tiene Statement la instrucción SQL es compilada cada vez que se usa. • Con PreparedStatement solo compila una vez. – Como se crea: • PreparedStatement stmt= conn.prepareStatement(sql); – Ejemplo: • sql = “SELECT * FROM productos WHERE id=? And fecha=?” • PreparedStatement stmt= conn.prepareStatement(sql); Capa Aplicación (PreparedStatement) • (continuación ejemplo) • sql = “SELECT * FROM productos WHERE id=? And fecha=?” – Parámetro 1 : id – Parámetro 2 : fecha • Como se pasan los parámetros – stmt.setInt(1,“10”); //Si quisiéramos el producto 10 – stmt.setDate(2,“03/09/2001”) //Los productos creados hoy. • Otros tipo de datos (setXXX) Metodo Tipo dato SQL setBoolean Bit setDate Date setDouble Double setFloat Float setString String,Varchar Capa Aplicación • CallableStatemet (Hereda de Statement) – Es usada para ejecutar StoredProcedure. – Proporciona métodos para mapear los parámetros de salida del Stored Procedure – Como se crea: • CallableStatement cs = conn.prepareCall("{call <StoredProc>}"); – Donde <StoredProc>, es el nombre del StoredProcedure • Métodos para mapear los parámetros – cs.registerOutParameter (indiceParametro, tipodato); • Ej.: cs.registerOutParameter( 1, java.sql.Date); Capa Aplicación • ResultSet – Tiene el mismo comportamiento de un cursor – Define los métodos, que permiten acceder al cursor generado como resultado de la ejecución de un SELECT. – El puntero esta ubicado antes de la primera fila. – Para moverse entre filas se emplea ResultSet.next() – Para obtener una columna especifica de la fila, se puede hacer invocando el método ResultSet.getXXX (xxx indica el tipo de datos) Capa Aplicación • ResultSet (Continuación) – Ejemplo: • • • • • • • String sql=“select * from productos” Statement stmt_ = conn.createStatemet(); ResultSet resultado_ = stmt_.executeQuery(sql); while(resultado_.next()){ System.out.println(“ id producto--> ”+resultado_.getInt(“id”)); System.out.println(“ producto--> ”+resultado_.getString(“nombre”)); } – Tipo de metodos getXXX Metodo Tipo dato SQL getBoolean Bit getDate Date getDouble Double getFloat Float getString String,Varchar Capa Aplicación • ResultSetMetaData – Contiene información acerca de las propiedades de cada una de las columnas, que conforman el cursor/tabla, que fue obtenida en la ejecución de una consulta. – Como se crea: • ResultSetMetaData rsmd = ResultSet.getMetaData(); • Ejemplo (Tomando como base el slide anterior): – ResultSet resultado = stmt.executeQuery(sql); – ResultSetMetaData metaData_ = resultado.getMetaData(); – Numero de Columnas: int cols = metadata.getColumnCount(); – Tipo Columna : String tipo = metadata.getColumnType(“id”); – Saber si un campo es auto incremento: • boolean esAutoIncremento = metadata.isAutoIncrement(); Conexión a la B.D. con JDBC String url = “jdbc:oracle:thin:@nut.javeriana.edu.co:1521:DEPTO” String usuario = “miNombre”; String password = “miClave”; Connection conexión = DriverManager. DriverManager getConnection(url,usuario,password); getConnection El driver manager intentará encontrar un driver cargado que pueda usar el protocolo especificado en la URL. Mediante la instancia de Connection (conexión) obtenida a través de getConnection se pueden ejecutar expresiones SQL. Conexión a la Base de Datos import java.sql.*; public class forNameLoader{ public static void main (String arg[]){ String url = “jdbc:oracle:thin:@nut.javeriana.edu.co:1521:DEPTO” String usuario = “miNombre”; String password = “miClave”; try{ DriverManager.registerDriver(new oracle.jdbc.driver.OracleDriver()); try{ Connection con = DriverManager.getConnection(url,usuario,password); if (con!=null) System.out.println("Driver cargado"); else System.out.println("Driver No cargado"); } catch(Exception e){System.out.println("Error en la conexion a la BD"); } } catch(Exception e){e.printStackTrace();} } } Conexión • Los tres métodos de conexión son: public static synchronized Connection getConnection(String url) throws SQLException public static synchronized Connection getConnection(String url, String user, String password) throws SQLException public static synchronized Connection getConnection(String url, Properties info) throws SQLException Operaciones sobre la base de Datos Statement declaracion = conexion.createStatement(); Statement st = con.createStatement(); // // operaciones con st // st.close(); import java.sql.*; public class forNameLoader{ public static void main (String arg[]){ String url = “jdbc:oracle:thin:@nut.javeriana.edu.co:1521:DEPTO” String usuario = “miNombre”; String password = “miClave”; try{ DriverManager.registerDriver(new oracle.jdbc.driver.OracleDriver()); try{ Connection con = DriverManager.getConnection(url,usuario,password); if (con!=null){ Statement st = con.createStatement(); // // operaciones con st // st.close(); } else System.out.println("Driver No cargado"); } catch(Exception e){System.out.println("Error en la conexion a la BD"); } } catch(Exception e){e.printStackTrace();} } } Ejemplo import java.sql.*; executeUpdate public class forNameLoader{ public static void main (String arg[]){ String url = “jdbc:oracle:thin:@nut.javeriana.edu.co:1521:DEPTO” String usuario = “miNombre”; String password = “miClave”; String query = “CREATE TABLE Paciente “ + “(id Number(9) NOT NULL PRIMARY KEY, ” + “nombre VarChar(50), apellido VarChar(50))”; try{ DriverManager.registerDriver(new oracle.jdbc.driver.OracleDriver()); try{ Connection con = DriverManager.getConnection(url,usuario,password); if (con!=null){ Statement st = con.createStatement(); int x = st.executeUpdate(query); System.out.println(“Tabla de pacientes creada”) st.close(); } else System.out.println("Driver No cargado"); } catch(Exception e){System.out.println("Error en la conexion a la BD"); } } catch(Exception e){e.printStackTrace();} } } Ejemplo import java.sql.*; executeQuery public class forNameLoader{ public static void main (String arg[]){ String url = “jdbc:oracle:thin:@nut.javeriana.edu.co:1521:DEPTO” String usuario = “miNombre”; String password = “miClave”; String query = SELECT * FROM Pacientes”; try{ DriverManager.registerDriver(new oracle.jdbc.driver.OracleDriver()); try{ Connection con = DriverManager.getConnection(url,usuario,password); if (con!=null){ Statement st = con.createStatement(); ResulSet y = st.executeQuery(query); while(y.next()){ // Lo que quieran con los datos } y.close(); st.close(); } else System.out.println("Driver No cargado"); } catch(Exception e){System.out.println("Error en la conexion a la BD"); } } catch(Exception e){e.printStackTrace();} } } JDBC En resumen, suponiendo que queremos revisar los datos de la tabla ’Temp' usamos: ... Statement sentencia = con.createStatement(); ResultSet vista = sentencia.executeQuery(“SELECT * FROM Temp”); while (vista.next()) { // Revisar el segundo campo de cada registro String unregistro = vista.getString(2); int unregistro = vista.getInt(“nombre_de_campo_numerico”); } Los métodos que permiten inspeccionar el ‘ResultSet’ aceptan el número del campo, contados a partir de uno, o el nombre del campo. JDBC Java intentará realizar las conversiones de tipos SQL a tipos Java de la forma más “razonable” posible. La correspondencia entre tipos SQL comunes y los tipos de Java se ilustran en las siguientes tablas: JDBC •Tipos de datos numéricos Java SQL byte int short long double double float TINYINT 8 bits INTEGER o INT 32 bits SMALLINT 16 bits BIGINT 64 bits DOUBLE 15 digitos de precisión FLOAT 15 digitos de precisión REAL 7 digitos de precisión java.math.BigDecimal NUMERIC java.math.BigDecimal DECIMAL Notas Números de precisión específica Números de precisión específica JDBC •Tipos de datos caracter Java SQL String String String CHAR o CHARACTER Cadena rellenada con espacios VARCHAR Cadena LONGVARCHAR Se puede leer usando un flujo de entrada BINARY La longitud del arreglo es la del campo VARBINARY La longitud del arreglo es la del campo LONGVARBINARY Se puede leer usando un flujo de entrada byte[] byte[] byte[] Notas JDBC Otros tipos de datos Java SQL Notas boolean java.sql.Data java.sql.Time java.sql.TimeStamp BIT DATE TIME TIMESTAMP true/false mm / dd / aa hh / mm / ss Fecha y hora en nanosegundos JDBC • Modelo de uso Connection conexión = null; Statement declaración = null; try { Class.forName(“sun.jdbc.odbc.JdbcOdbcDriver”); conexión = DriverManager.getConnection(“jdbc:odbc:NombreBD”, “idUsuario”, “contraseña”); declaración = conexión.createStatement(); ResultSet resultado = declaración.executeQuery(“instrucción SQL”); while (resultado.next()) { int campoEntero = resultado.getInt(“NombreCampoEntero”); int campoReal = resultado.getString(“NombreCampoReal”); System.out.println(campoEntero + “ “ + campoReal); } } catch (ClassNotFoundException e) { System.err.println(“Controlador no encontrado”); } catch (SQLException e) { System.err.println(“Falla en la Base de Datos”); } JDBC • Usando excepciones // ExcepcionesEnJDBC import java.sql.*; Parte 1/2 public class ExcepcionesEnJDBC { public static void main(String argv[]) { Connection conexión = null; Statement declaración = null; try { Class.forName(“sun.jdbc.odbc.JdbcOdbcDriver”); } catch(ClassNotFoundException e) { System.err.println(“Error: controlador no encontrado.”); System.exit(1); } try { conexión = DriverManager.getConnection(“jdbc:odbc:NombreBD”, “idUsuario”, “contraseña”); } catch (SQLException e) { System.err.println(“Error: falla en conexión a la base de datos.”); System.exit(2); } JDBC // ExcepcionesEnJDBC Parte 2/2 try { declaración = conexión.createStatement(); } catch (SQLException e) { System.err.println(“Error: imposible crear la declaración.”); System.exit(3); } try { ResultSet resultado = declaración.executeQuery(“instrucción SELECT-SQL”); while (resultado.next()) { int campoEntero = resultado.getInt(“NombreCampoEntero”); int campoReal = resultado.getString(“NombreCampoReal”); System.out.println(campoEntero + “ “ + campoReal); } } catch(SQLException e) { System.err.println(“Error: en lectura de la Base de Datos”); } } } JDBC Declaraciones preparadas. Una declaración preparada es una consulta especial en la que se mantiene la estructura y se cambia solamente el dato que se requiera. SELECT * FROM NombreTabla WHERE campo=variable SELECT * FROM NombreTabla WHERE campo=? Connection conexión = null; Statement declaración = null; ... PreparedStatement declaraciónPreparada = conexión.prepareStatement( “SELECT * FROM NombreTabla WHERE campo=?”); declaraciónPreparada.setString(n, “valorCampo”); ... ResultSet resultado = declaraciónPreparada.executeQuery(); Recursos – Sitio oficial JDBC • java.sun.com/jdbc – Buscar drivers. • http://industry.java.sun.com/products/jdbc/drivers – Tutorial JDBC • http://java.sun.com/j2se/1.3/docs/guide/jdbc/getstart/Gettin gStartedTOC.fm.html – Otros sitios de interes • www.theserverside.com • www.jdance.com • www.jguru.com