Base de Datos Oracle: desarrollo de aplicaciones JDBC Contenidos jul-04 Introducción Drivers Conexión Ejecución de sentencias ResultSets y Cursores Transacciones Control de errores Alberto M.F.A. [email protected] 2 Características API Java OO que provee acceso universal a DBMS relacionales JDBC 3.0 también acceso a datos NO Relacionales Simplifica envío de sentencias SQL a DBMS NO estandariza el SQL, se pasa al driver jul-04 Alberto M.F.A. [email protected] 3 Versiones de SQL Formas de afrontar: jul-04 Pasa el SQL directamente al driver Se ajusta a las secuencias de escape ODBC Interfaz DatabaseMataData. El programa puede averiguar las capacidades del driver. Todos los drivers deben soportar al menos ANSI SQL-92 Entry Level Alberto M.F.A. [email protected] 4 Arquitectura JDBC jul-04 Alberto M.F.A. [email protected] 5 JDK Java En el JDK SUN provee: En WEB: jul-04 JDBC DriverManager JDBC-ODBC Bridge JDBC driver test suite. Para homologar drivers http://java.sun.com/products/jdbc Alberto M.F.A. [email protected] 6 Versiones de JDBC JDBC 1.0 JDBC 2.0 Scrollable y updatable result sets Pooling de conexiones Oracle 8i es JDBC 2.1 JDBC 2.0 JDBC 3.0 SavePoints Claves autogeneradas Pooled statements, etc jul-04 Alberto M.F.A. [email protected] 7 Modelo de objetos Statement <excuteQuery> <crea> Connection PreparedStatement ResultSet CallableStatement jul-04 Alberto M.F.A. [email protected] 8 Contenidos Introducción Drivers Conexión Ejecución de sentencias ResultSets y Cursores Transacciones Control de errores jul-04 Alberto M.F.A. [email protected] 9 Drivers Suministrados por los fabricantes Cuatro tipos distintos: jul-04 (1) (2) (3) (4) JDBCODBC + driver ODBC JDBCAPI nativo JDBCProtocolo Middleware JDBCProtocolo Nativo Alberto M.F.A. [email protected] 10 Drivers tipo 1 Para acceso desde Windows cualquier DBMS que no tiene JDBC Debe haber un driver ODBC instalado en el equipo que accede a DBMS. No apto para conectar desde applets Solución de primera mano si no hay otra forma jul-04 Alberto M.F.A. [email protected] 11 Drivers tipo 1 Aplicación Driver JDBC ODBC Driver ODBC Programador SUN, JDK Microsoft Fabricante DBMS jul-04 Alberto M.F.A. [email protected] DBMS Máquina cliente 12 Drivers tipo 2 El driver JDBC delega en las librerías del API nativo (OCI por ejemplo) También exige que en la máquina que accede esté instalado el driver adecuado. Tampoco es apto para Applets. Puede dar buen rendimiento, delega con JNI en el API. jul-04 Alberto M.F.A. [email protected] 13 Drivers tipo 2 Driver JDBC Aplicación API Nativo DBMS Programador Fabricante DBMS JNI jul-04 Alberto M.F.A. [email protected] Máquina cliente 14 Drivers tipo 3 Entre el cliente y el DBMS hay un servidor middleware conversor. El driver convierte llamadas JDBC a un protocolo intermedio. El servidor middleware traduce a llamadas al protocolo nativo del DBMS. Solución cómoda para el fabricante, facilita hacer muchos interfaces. jul-04 Alberto M.F.A. [email protected] Máquina cliente Drivers tipo 3 Aplicación Driver JDBC 15 Servidor Middleware DBMS Programador Fabricante DBMS Protocolo Nativo Otra Máquina Protocolo Intermedio jul-04 Alberto M.F.A. [email protected] 16 Drivers tipo 4 Driver JDBC traduce al protocolo nativo del DBMS. Se obtiene buen rendimiento. El cliente es independiente de plataforma e instalación (Applet). La JVM descarga todas las clases del driver según demanda. jul-04 Alberto M.F.A. [email protected] 17 Drivers tipo 4 Driver JDBC Aplicación DBMS Programador Fabricante DBMS Protocolo Nativo jul-04 Alberto M.F.A. [email protected] Máquina cliente 18 JDBC de Oracle Thin Driver, de tipo 4 OCI driver, de tipo 2 El DBMS incluye una JVM, para ella: jul-04 Server-side thin driver Server-side internal driver Alberto M.F.A. [email protected] 19 JVM de Oracle Admite procedimientos almacenados en JAVA. Estos pueden conectarse a otros servidores. Incluye un contenedor J2EE de EJB’s. jul-04 Incrusta la capa de lógica de negocio en la base de datos. Los drivers JDBC está optimizados para la conexión interna. Alberto M.F.A. [email protected] 20 Diagrama de drivers jul-04 Alberto M.F.A. [email protected] 21 Contenidos jul-04 Introducción Drivers Conexión Ejecución de sentencias ResultSets y Cursores Transacciones Control de errores Alberto M.F.A. [email protected] 22 Conexión Tres alternativas: Usando el DriverManager Usando un DataSource Instanciando el Driver Directamente Tras el proceso se obtiene un objeto de la Clase Connection jul-04 Alberto M.F.A. [email protected] 23 Conexión con DriverManager Registra todos los drivers JDBC jul-04 El driver a usar debe ser registrado previamente Al crear la conexión se le indica el URL del driver El DM localiza el driver adecuado buscando el URL entre los que tiene registrados Alberto M.F.A. [email protected] 24 URL de driver <protocol>:<sub-protocol>:<subname> <protocol> Siempre JDBC <sub-protocol> Nombre del driver o mecanismo <subname> Dependiente de sub-protocol. Indicación de cómo abrir sesión (User, Pass, Server, DataSource, alias, etc) jdbc:odbc:<miConexion> jdbc:oracle:oci8:@<instancia> jdbc:oracle:thin:@<maquina>:1521:<instancia> jul-04 Alberto M.F.A. [email protected] 25 Ejemplo con DriverManager DriverManager.registerDriver( new oracle.jdbc.driver.OracleDriver() ); conn = DriverManager.getConnection( “jdbc:oracle:oci8:@desa” , “scott” , “tiger” ); jul-04 Alberto M.F.A. [email protected] 26 DataSource Desde JDBC 2.0. Representa cualquier fuente de datos (Como si fuese un alias o DSN ODBC). Muchas similitudes con DriverManager Importantes diferencias: Se registra en un árbol JNDI Permite gestionar pools de conexiones jul-04 Independencia del programa Aumenta la eficiencia si se abren y cierran muchas conexiones Transacciones distribuidas Alberto M.F.A. [email protected] 27 Registro en JNDI Se registra bajo una clave la conexión, el driver y sus particularidades para un DBMS El programa pregunta por la clave. Es un nivel de indirección que independiza el programa de la DBMS. jul-04 Si mañana cambia la DBMS, se cambia en el JNDI, el código del programa no se entera. Alberto M.F.A. [email protected] 28 Propiedades de DataSource jul-04 dataSourceName databaseName description networkProtocol user password serverName port Crear un DataSource Especificar esto Registrar en JNDI bajo un nombre “miBD” Programa pide getConnection(“miBD”) Alberto M.F.A. [email protected] 29 Ejemplo con DataSource DataSource ds = (DataSource)ctx.lookup( "jdbc/miDB"); Connection con = ds.getConnection(); jul-04 Alberto M.F.A. [email protected] 30 Responsabilidades Connection Representar y cerrar sesión Control de transacciones. Committ y RollBack Creación de objetos sentencia: jul-04 Statement. Para SQL sin parámetros. PreparedStatement. SQL con parámetros de entrada y/o ejecución repetida. CallableStatement. Llamadas a proc. Almacenados y parametros de IN/OUT Alberto M.F.A. [email protected] 31 Contenidos jul-04 Introducción Drivers Conexión Ejecución de sentencias ResultSets y Cursores Transacciones Control de errores Alberto M.F.A. [email protected] 32 Statement Connection con = DriverManager.getConnection(...); Statement stmt = con.createStatement(); ResultSet rs = stmt.executeQuery( “SELECT a, b, c FROM Table2” ); jul-04 Alberto M.F.A. [email protected] 33 Formas ejecución Statement executeQuery(<SQL>, ...) executeUpdate(<SQL>, ...) Ejecutar sentencias DDL y DML Devuelve (int) el nº de filas afectas execute(<SQL>, ...) jul-04 Para ejecutar consultas: “SELECT ...” Siempre devuelve un ResultSet Devuelve varios ResulSet’s o int’s. Alberto M.F.A. [email protected] 34 Ejecución en Batch Statement stmt = con.createStatement(); con.setAutoCommit(false); stmt.addBatch("INSERT INTO emp VALUES …"); stmt.addBatch("INSERT INTO dep VALUES …"); stmt.addBatch("INSERT INTO emp_dept VALUES …"); int [] updateCounts = stmt.executeBatch(); jul-04 Alberto M.F.A. [email protected] 35 PreparedStatement Sentencias SQL precompiladas Si se van a repetir se deben pasar datos nuevos en cada ejecución jul-04 Mayor rendimiento si se van a ejecutar repetidas veces Admite parámetros de entrada Solo parámetros de entrada Alberto M.F.A. [email protected] 36 Ejemplos PreparedStatement PreparedStatement pstmt = con.prepareStatement( "UPDATE table4 SET m = ? WHERE x = ?” ); ... pstmt.executeUpdate(); PreparedStatement pstmt2 = con.prepareStatement( "SELECT a, b, c FROM Table1”); ResultSet rs = pstmt2.executeQuery(); jul-04 Alberto M.F.A. [email protected] 37 Formas ejecución preparedStatement executeQuery(...) Ejecutar sentencias DDL y DML Devuelve (int) el nº de filas afectas execute(...) jul-04 Para ejecutar consultas: “SELECT ...” Siempre devuelve un ResultSet executeUpdate(...) Sin SQL Devuelve varios ResulSet’s o int’s. Alberto M.F.A. [email protected] 38 Valores de parámetros prstmt.set<TIPO>(<pos>,<valor>); Cada placeholder (?) en el SQL debe ser ajustado antes de llamar a execute<>() La clase PreparedStatement tiene setters para todos los tipos básicos java jul-04 setInt, setLong, setFloat, setString, ... Alberto M.F.A. [email protected] 39 Parámetros <pos> Se refiere a la posición del ? en la sentencia PreparedStatement pstmt = con.prepareStatement( "UPDATE table4 SET m = ? WHERE x = ?” ); pstmt.setString(1, “Valor”); pstmt.setInt(2, 25); pstmt.executeUpdate(); jul-04 Alberto M.F.A. [email protected] 40 Parámetros nulos Método pstmt.setNull(...) Posición del parámetro Tipo de dato SQL pstmt.setNull(3, java.sql.Types.VARCHAR); jul-04 Alberto M.F.A. [email protected] 41 CallableStatement Sentencias que llaman a procedimientos almacenados Pueden devolver jul-04 Procedimientos o funciones ResultSet Valores discretos en parámetros OUT e INOUT Sintaxis ODBC para invocar a proc’s. Alberto M.F.A. [email protected] 42 Ejemplo CallableStatement cstmt = con.prepareCall( "{call updatePrices(?, ?)}” ); cstmt.setString(1, “xyz"); cstmt.setFloat(2, 8.49f); cstmt.executeUpdate(); jul-04 Alberto M.F.A. [email protected] 43 Sintaxis ODBC {[? =] call procedure_name[(?, ?, ...)]} “{call procedure}” “{call procedure(?, ?)}” “{? = call function}” “{? = call function(?, ?)}” jul-04 Alberto M.F.A. [email protected] 44 Ejecución De la misma forma que preparedStatement Hay jerarquía de herencia jul-04 Statement PreparedStatement extends Statement CallableStatement extends PreparedStatement Alberto M.F.A. [email protected] 45 Parámetros IN jul-04 De IN de la misma forma que preparedStatement Indicación de NULL en datos de entrada igual. Alberto M.F.A. [email protected] 46 Parámetros OUT Se referencian también por posición Deben ser registrados ANTES de la ejecución. jul-04 registerOutParameter(...) Alberto M.F.A. [email protected] 47 Ejemplo parámetros OUT CallableStatement cstmt = con.prepareCall( "{call getTestData(?, ?)}"); cstmt.registerOutParameter(1, java.sql.Types.TINYINT); cstmt.registerOutParameter(2, java.sql.Types.DECIMAL); ResultSet rs = cstmt.executeQuery(); // . . . byte x = cstmt.getByte(1); jul-04 Alberto M.F.A. [email protected] 48 Parámetros OUT nulos Se detectan con el método callableStatement.wasNull() Debe ser llamado después del getter byte x = cstmt.getByte(1); if (cstmt.wasNull()) { . . . Puede que el manipulador del resultado sepa tratar con valores null. jul-04 Alberto M.F.A. [email protected] 49 Parámetros INOUT Referenciados por posición Combinación de las dos formas jul-04 Método set<TIPO>(<pos>, <valor>) registerOutParameter(...) execute[<modo>]() Método get<TIPO>(<pos>) Alberto M.F.A. [email protected] 50 Ejemplo parámetros INOUT CallableStatement cstmt = con.prepareCall( "{call reviseTotal(?)}"); cstmt.setByte(1, (byte)25); cstmt.registerOutParameter(1, java.sql.Types.TINYINT); cstmt.executeUpdate(); byte x = cstmt.getByte(1); jul-04 Alberto M.F.A. [email protected] 51 Contenidos jul-04 Introducción Drivers Conexión Ejecución de sentencias ResultSets y Cursores Transacciones Control de errores Alberto M.F.A. [email protected] 52 ResultSet Conjunto de filas + cursor Devuelto en todos los métodos executeQuery(...) jul-04 Alberto M.F.A. [email protected] 53 ResultSet + cursor Posición inicial jul-04 Alberto M.F.A. [email protected] 54 Ejemplo ResultSet stmt = con.createStatement(); ResultSet rs = stmt.executeQuery( "SELECT a, b, c FROM Table1"); while (rs.next()) { int i = rs.getInt("a"); String s = rs.getString("b"); float f = rs.getFloat("c"); System.out.println(i+" "+s+" "+f); } jul-04 Alberto M.F.A. [email protected] 55 Cursores Indican la fila activa del ResultSet Pueden ser: Por defecto solo FORWARD (menos recursos) Para crearlos bidireccionales: jul-04 Solo hacia delante Bidireccionales Indicación expresa en Connection al crear la sentencia Alberto M.F.A. [email protected] 56 Movimientos de Cursor rs.beforeFirst() rs.afterLast() rs.next() rs.previous() rs.isBeforeFirst() rs.isAfterLast() rs.isFirst() rs.isLast() jul-04 movimiento control Alberto M.F.A. [email protected] 57 Datos de columnas Métodos getter: rs.get<TIPO>(<indicacion>); <indicacion> Señala la columna Por posición Por nombre String s = rs.getString(2); String s = rs.getString("TITLE"); jul-04 Alberto M.F.A. [email protected] 58 Tipos de ResultSet Según: Movimiento del cursor Si permiten ver cambios hechos por otros usuarios mientras está abierto 3 tipos: TYPE_FORWARD_ONLY TYPE_SCROLL_INSENSITIVE TYPE_SCROLL_SENSITIVE jul-04 Alberto M.F.A. [email protected] 59 Tipos de Concurrencia Forma en la que varios usuarios trabajan sobre los mimos datos: CONCUR_READ_ONLY CONCUR_UPDATABLE jul-04 Impone bloqueo de lectura Impone bloqueo de escritura UPDATABLE restringe mucho la concurrencia. Se debe administrar con mucha cautela Alberto M.F.A. [email protected] 60 Retenibilidad (Holdability) Los ResultSet podrían permanecer en memoria del cliente después de terminar la transacción que los creó. Dos modos: ResultSet.HOLD_CURSORS_OVER_COMMIT ResultSet.CLOSE_CURSORS_AT_COMMIT jul-04 Alberto M.F.A. [email protected] 61 Tipos por defecto Movimiento del cursor Concurrencia CONCUR_READ_ONLY Holdability jul-04 TYPE_FORWARD_ONLY Depende del driver consultar DatabaseMetadata Alberto M.F.A. [email protected] 62 Creación de otros tipos de RS A partir de JDBC 2.0 Se indica al objeto Connection al pedir una Statement Statement stmt = con.createStatement( ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_UPDATABLE, ResultSet.HOLD_CURSORS_OVER_COMMIT ); jul-04 Alberto M.F.A. [email protected] 63 Otro ejemplo PreparedStatement pstmt = con.prepareStatement( "SELECT EMP_NO, SALARY FROM EMPLOYEES WHERE EMP_NO = ?", ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_UPDATABLE, ResultSet.HOLD_CURSORS_OVER_COMMIT ); jul-04 Alberto M.F.A. [email protected] 64 Actualización de datos Si el rs es CONCUR_UPDATABLE Sin usar SQL int n = rs.getInt(3); rs.updateInt(3, 88); n = rs.getInt(3); // n = 88 rs.updateString("ADDRESS", "321 Kasten"); jul-04 Alberto M.F.A. [email protected] 65 Borrado de filas jul-04 Si el rs es CONCUR_UPDATABLE Se debe posicionar el cursor en la fila a borrar rs.deleteRow(); Alberto M.F.A. [email protected] 66 Inserción de nuevas filas Los RS actualizables tienen una fila especial para inserciones Se coloca el cursor en ella y “updates” rs.moveToInsertRow(); rs.updateObject(1, myArray); rs.updateInt(2, 3857); rs.updateString(3, "Mysteries"); rs.insertRow(); rs.first(); jul-04 Alberto M.F.A. [email protected] 67 Contenidos jul-04 Introducción Drivers Conexión Ejecución de sentencias ResultSets y Cursores Transacciones Control de errores Alberto M.F.A. [email protected] 68 Transacciones jul-04 Por defecto la Connection está con: connection.AutoCommitMode = TRUE Cada sentencia que se ejecuta es una transacción. Para TRX largas: connection.AutoCommitMode = FALSE Alberto M.F.A. [email protected] 69 Transacciones distribuidas jul-04 Solo posible con Connection obtenidas a través de DataSource Si son para distribuidas AutoCommitMode=FALSE Alberto M.F.A. [email protected] 70 Nivel de aislamiento en TRX Cuando dos TRX coinciden ¿cómo se comportan? 4 niveles: jul-04 Connection.TRANSACTION_READ_UNCOMMITTED Connection.TRANSACTION_READ_COMMITTED Connection.TRANSACTION_REPEATABLE_READ Connection.TRANSACTION_SERIALIZABLE Depende de DBMS que niveles se soportan Método setTransactionIsolation(...) Alberto M.F.A. [email protected] 71 Contenidos jul-04 Introducción Drivers Conexión Ejecución de sentencias ResultSets y Cursores Transacciones Control de errores Alberto M.F.A. [email protected] 72 Control de errores (try catch) Uso adecuado del mecanismo de Excepciones Java Las operaciones JDBC “levantan” excepciones de tipo SQLException try{ ... Código JDBC }catch(SQLException e){ ... Control del error } jul-04 Alberto M.F.A. [email protected] 73 Control de errores (try finally) try{ ... Código JDBC } finally { ... Acción con o sin error Cerrar siempre RS, Stmt y Connection } jul-04 Alberto M.F.A. [email protected] 74 Mapeado de SQL a Java El driver debe mapear: jul-04 Tipos java a tipos java.sql.Types.XXXX java.sql.Types.XXXX a tipos nativos del DBMS En la documentación de SUN y del fabricante del driver se especifican las equivalencias Alberto M.F.A. [email protected] 75