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. alb@lsi.uniovi.es 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. alb@lsi.uniovi.es 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. alb@lsi.uniovi.es 4 Arquitectura JDBC jul-04 Alberto M.F.A. alb@lsi.uniovi.es 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. alb@lsi.uniovi.es 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. alb@lsi.uniovi.es 7 Modelo de objetos Statement <excuteQuery> <crea> Connection PreparedStatement ResultSet CallableStatement jul-04 Alberto M.F.A. alb@lsi.uniovi.es 8 Contenidos Introducción Drivers Conexión Ejecución de sentencias ResultSets y Cursores Transacciones Control de errores jul-04 Alberto M.F.A. alb@lsi.uniovi.es 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. alb@lsi.uniovi.es 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. alb@lsi.uniovi.es 11 Drivers tipo 1 Aplicación Driver JDBC ODBC Driver ODBC Programador SUN, JDK Microsoft Fabricante DBMS jul-04 Alberto M.F.A. alb@lsi.uniovi.es 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. alb@lsi.uniovi.es 13 Drivers tipo 2 Driver JDBC Aplicación API Nativo DBMS Programador Fabricante DBMS JNI jul-04 Alberto M.F.A. alb@lsi.uniovi.es 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. alb@lsi.uniovi.es 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. alb@lsi.uniovi.es 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. alb@lsi.uniovi.es 17 Drivers tipo 4 Driver JDBC Aplicación DBMS Programador Fabricante DBMS Protocolo Nativo jul-04 Alberto M.F.A. alb@lsi.uniovi.es 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. alb@lsi.uniovi.es 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. alb@lsi.uniovi.es 20 Diagrama de drivers jul-04 Alberto M.F.A. alb@lsi.uniovi.es 21 Contenidos jul-04 Introducción Drivers Conexión Ejecución de sentencias ResultSets y Cursores Transacciones Control de errores Alberto M.F.A. alb@lsi.uniovi.es 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. alb@lsi.uniovi.es 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. alb@lsi.uniovi.es 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. alb@lsi.uniovi.es 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. alb@lsi.uniovi.es 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. alb@lsi.uniovi.es 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. alb@lsi.uniovi.es 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. alb@lsi.uniovi.es 29 Ejemplo con DataSource DataSource ds = (DataSource)ctx.lookup( "jdbc/miDB"); Connection con = ds.getConnection(); jul-04 Alberto M.F.A. alb@lsi.uniovi.es 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. alb@lsi.uniovi.es 31 Contenidos jul-04 Introducción Drivers Conexión Ejecución de sentencias ResultSets y Cursores Transacciones Control de errores Alberto M.F.A. alb@lsi.uniovi.es 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. alb@lsi.uniovi.es 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. alb@lsi.uniovi.es 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. alb@lsi.uniovi.es 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. alb@lsi.uniovi.es 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. alb@lsi.uniovi.es 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. alb@lsi.uniovi.es 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. alb@lsi.uniovi.es 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. alb@lsi.uniovi.es 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. alb@lsi.uniovi.es 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. alb@lsi.uniovi.es 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. alb@lsi.uniovi.es 43 Sintaxis ODBC {[? =] call procedure_name[(?, ?, ...)]} “{call procedure}” “{call procedure(?, ?)}” “{? = call function}” “{? = call function(?, ?)}” jul-04 Alberto M.F.A. alb@lsi.uniovi.es 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. alb@lsi.uniovi.es 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. alb@lsi.uniovi.es 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. alb@lsi.uniovi.es 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. alb@lsi.uniovi.es 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. alb@lsi.uniovi.es 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. alb@lsi.uniovi.es 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. alb@lsi.uniovi.es 51 Contenidos jul-04 Introducción Drivers Conexión Ejecución de sentencias ResultSets y Cursores Transacciones Control de errores Alberto M.F.A. alb@lsi.uniovi.es 52 ResultSet Conjunto de filas + cursor Devuelto en todos los métodos executeQuery(...) jul-04 Alberto M.F.A. alb@lsi.uniovi.es 53 ResultSet + cursor Posición inicial jul-04 Alberto M.F.A. alb@lsi.uniovi.es 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. alb@lsi.uniovi.es 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. alb@lsi.uniovi.es 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. alb@lsi.uniovi.es 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. alb@lsi.uniovi.es 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. alb@lsi.uniovi.es 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. alb@lsi.uniovi.es 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. alb@lsi.uniovi.es 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. alb@lsi.uniovi.es 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. alb@lsi.uniovi.es 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. alb@lsi.uniovi.es 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. alb@lsi.uniovi.es 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. alb@lsi.uniovi.es 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. alb@lsi.uniovi.es 67 Contenidos jul-04 Introducción Drivers Conexión Ejecución de sentencias ResultSets y Cursores Transacciones Control de errores Alberto M.F.A. alb@lsi.uniovi.es 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. alb@lsi.uniovi.es 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. alb@lsi.uniovi.es 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. alb@lsi.uniovi.es 71 Contenidos jul-04 Introducción Drivers Conexión Ejecución de sentencias ResultSets y Cursores Transacciones Control de errores Alberto M.F.A. alb@lsi.uniovi.es 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. alb@lsi.uniovi.es 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. alb@lsi.uniovi.es 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. alb@lsi.uniovi.es 75