0
JDBC Java Database Connectivity
Bibliografía <ul><li>JDBC API Tutorial and Reference, Third Edition . Maydene Fisher  et al.   Addison-Wesley Pub Co; 3rd ...
Objetivos <ul><li>Profundizar en la estrategia de programación CLI, particularizando para Java </li></ul><ul><ul><li>Conoc...
Agenda <ul><li>Introducción </li></ul><ul><li>Drivers JDBC </li></ul><ul><li>La clase  DriverManager </li></ul><ul><li>Con...
Introducción <ul><li>JDBC es un conjunto de clases e  interfaces  Java para la ejecución de sentencias SQL ( ver JavaDoc )...
Proceso de trabajo con JDBC Aplicación JDBC Driver A Connection Statement Gestor de drivers Driver B ResultSet    getConn...
<ul><li>El proceso de trabajo en JDBC consiste en: </li></ul><ul><ul><li>Conectarse a la base de datos ( DriverManager ). ...
Agenda <ul><li>Introducción </li></ul><ul><li>Drivers JDBC </li></ul><ul><li>La clase  DriverManager </li></ul><ul><li>Con...
El driver JDBC <ul><li>JDBC es básicamente una colección de interfaces Java (paquete   java.sql ). P.ej. </li></ul><ul><ul...
Tipos de drivers <ul><li>Tipo 1: Puente JDBC-ODBC </li></ul><ul><ul><li>Traduce JDBC a ODBC y lo retransmite al driver ODB...
Tipos de drivers (II) <ul><li>Tipo 3: Driver Java sobre red </li></ul><ul><ul><li>Traduce las llamadas JDBC a un protocolo...
Tipos de drivers (III) Driver  ODBC
El interface  Driver  y  la clase  DriverManager <ul><li>El interface  Driver  especifica los métodos que todo driver JDBC...
Agenda <ul><li>Introducción </li></ul><ul><li>Drivers JDBC </li></ul><ul><li>La clase  DriverManager </li></ul><ul><li>Con...
Clase  DriverManager <ul><li>Es la capa de gestión de JDBC </li></ul><ul><li>Se sitúa entre la aplicación que usará JDBC y...
Proceso de trabajo con JDBC Aplicación JDBC Driver A Connection Statement Gestor de drivers Driver B ResultSet    getConn...
Mantenimiento de la lista de drivers <ul><li>¿Cómo se forma la lista de drivers disponibles? </li></ul><ul><li>Toda clase ...
Dónde poner el  forName <ul><li>El driver se debe registrar una única vez durante la vida de la aplicación </li></ul><ul><...
Obtención de conexiones <ul><li>Es el  Driver  concreto el que realiza las conexiones, pero las solicitudes de conexión se...
Agenda <ul><li>Introducción </li></ul><ul><li>Drivers JDBC </li></ul><ul><li>La clase  DriverManager </li></ul><ul><li>Con...
El interface  Connection <ul><li>Un objeto de tipo  Connection  representa  una sesión abierta con una base de datos. </li...
URLs en JDBC <ul><li>Uno de los parámetros del método  getConnection  indica la URL (con protocolo  jdbc ) que permite loc...
Ejemplo de código de conexión a Oracle try  { Class.forName(&quot;oracle.jdbc.driver.OracleDriver&quot;); }  catch  (Class...
Importante <ul><li>La aplicación no suele trabajar directamente con el  Driver  concreto. </li></ul><ul><li>Le pide al  Dr...
 
Agenda <ul><li>Introducción </li></ul><ul><li>Drivers JDBC </li></ul><ul><li>La clase  DriverManager </li></ul><ul><li>Con...
El interface  Statement <ul><li>Los objetos  Statement  permiten la ejecución de sentencias SQL y obtener los resultados. ...
El interface  Statement   (II) <ul><li>El Método  executeQuery  devuelve un objeto de tipo  ResultSet </li></ul><ul><ul><l...
El interface  Statement   (III) <ul><li>Una vez que el resultado haya sido procesado se debe cerrar el  Statement  mediant...
Ejemplo de código para Oracle // Carga del driver (Class.forName ... Connection con =  null ; try  { String url = &quot;jd...
Composición del SQL <ul><li>El SQL que aceptan los métodos  executeXxx  es un String (JDBC es CLI) </li></ul><ul><li>Puede...
El interface  ResultSet <ul><li>Los objetos de tipo  ResultSet  ofrecen métodos para recorrer el resultado de una consulta...
El interface  ResultSet  (II) <ul><li>Se obtienen los valores de la fila actual utilizando las distintas versiones del mét...
ResultSet  y valores nulos <ul><li>Cuando se ha leído un  null  de SQL usando uno de los métodos  get<tipo> , éste devuelv...
Navegación por el  ResultSet <ul><li>En principio sólo se puede avanzar por las filas de datos ( next() ) </li></ul><ul><l...
Tipos de datos y  get<Tipo> <ul><li>Una “x” indica que el método  get <tipo>  puede legalmente usarse para recuperar el ti...
Tipos de datos y  get<Tipo> 
Ejemplo completo try  { Class.forName(&quot;oracle.jdbc.driver.OracleDriver&quot;); }  catch  (ClassNotFoundException e) {...
Ejemplo completo (II) ... rs.close(); stmt.close(); }  catch  (SQLException e) { e.printStackTrace(); }  finally  { try  {...
Ejemplo de prácticas package  sol; import  bd.AbstractDBManager; import  java.sql.*; import  model.*; public   class  Gest...
public  Articulo getArticulo(String codigo) { Articulo articulo =  null ; Connection con =  null ; try { con =  DriverMana...
El interface  PreparedStatement <ul><li>Cada vez que se lanza un  Statement  el SGBD debe interpretarla y calcular un plan...
El interface  PreparedStatement <ul><li>Otro uso de  PreparedStatement  es la posibilidad de parametrizar las consultas </...
Inyección de SQL <ul><li>Detrás de un formulario de autenticación habrá una consulta como: </li></ul><ul><ul><li>SELECT * ...
El interface  PreparedStatement <ul><li>Antes de que la sentencia SQL pueda ser ejecutada deberemos asignar algún valor a ...
Ejemplo try  { Class.forName(&quot;oracle.jdbc.driver.OracleDriver&quot;); }  catch  (ClassNotFoundException e) { System.e...
Ejemplo (II) }  catch  (SQLException e) { e.printStackTrace(); }  finally  { try  { if  (con !=  null ) con.close(); }  ca...
Parámetros con valores  null <ul><li>Cuando se pasa un valor  null  Java en alguno de los métodos  set<tipo>() , se almace...
Notas sobre fechas (Oracle) <ul><li>Al almacenar fechas en Oracle podemos perder precisión </li></ul><ul><li>Oracle tiene ...
El interface  CallableStatement <ul><li>Los objetos  CallableStatement  proporcionan un mecanismo para invocación de store...
Ejemplo <ul><li>Supongamos una función llamada  PrecioArticulo  que devuelve el precio de una cantidad de artículos </li><...
Ejemplo (II) <ul><li>Un procedimiento ( swap ) de intercambio de valores (dos parámetros INOUT) </li></ul>// Carga del dri...
Agenda <ul><li>Introducción </li></ul><ul><li>Drivers JDBC </li></ul><ul><li>La clase  DriverManager </li></ul><ul><li>Con...
Transacciones en JDBC <ul><li>Una transacción es un conjunto de sentencias que se deben completar o anular en su totalidad...
Transacciones en JDBC <ul><li>El modo autoCommit se activa/desactiva con el método  setAutoCommit(boolean on)  del interfa...
Ejemplo ... Carga del driver ... String URL = &quot;jdbc:oracle:thin:@localhost:1521:PBD&quot;; Connection con =  null ; t...
Ejemplo (II) }  catch  (SQLException e) { e.printStackTrace(); try  { if  (con !=  null )  con.rollback(); }  catch  (SQLE...
Control de la concurrencia <ul><li>¿Que ocurre cuando un proceso está realizando una transacción (no se sabe si la confirm...
Control de la concurrencia (II) <ul><ul><li>TRANSACTION_REPEATABLE_READ : Solo se leen datos cofirmados. Además mantiene u...
Agenda <ul><li>Introducción </li></ul><ul><li>Drivers JDBC </li></ul><ul><li>La clase  DriverManager </li></ul><ul><li>Con...
SQLException <ul><li>La mayoría de los métodos de las clases e interfaces JDBC lanzan la excepción  java.sql.SQLException ...
Agenda <ul><li>Introducción </li></ul><ul><li>Drivers JDBC </li></ul><ul><li>La clase  DriverManager </li></ul><ul><li>Con...
DatabaseMetaData <ul><li>La conexión proporciona información sobre la BD a la que se conecta </li></ul><ul><li>Para ello d...
ResultSetMetaData <ul><li>ResultSet proporciona información, además de sobre el contenido, sobre la estructura de los dato...
Secuencias de escape <ul><li>Los  Statement  pueden contener SQL con sintaxis de escape SQL.  </li></ul><ul><li>La sintaxi...
Sobre conexiones <ul><li>Las conexiones son un recurso limitado:  hay que cerrarlas </li></ul><ul><li>Pero cuando? ¿Tras c...
Pool de Conexiones Aplicación DriverManager new  Connection( con.close() Pool de Conexiones getConnection( getConnection(
Cuando usar  PreparedStatement <ul><li>No todos los SGBDs lo soportan </li></ul><ul><li>En principio mejoran el rendimient...
<ul><li>“ The use of a Statement in JDBC should be 100% localized to being used for DDL (ALTER, CREATE, GRANT, etc) as the...
Agenda <ul><li>Introducción </li></ul><ul><li>Drivers JDBC </li></ul><ul><li>La clase  DriverManager </li></ul><ul><li>Con...
Actualizaciones por lotes <ul><li>Ejecutar un conjunto de actualizaciones de “una tacada”.  </li></ul><ul><li>No se pueden...
ResultSet  recorrible y actualizable <ul><li>Con el  ResultSet  tradicional sólo se puede avanzar por los datos </li></ul>...
ResultSet  recorrible y actualizable (II) <ul><li>Los movimientos se realizan con los métodos  next() ,  previous() ,  rel...
Nuevos tipos de datos <ul><li>Se pueden recuperar/almacenar en una base de datos objetos de tipo </li></ul><ul><ul><li>BLO...
javax.sql <ul><li>Incluye las extensiones JDBC para J2EE </li></ul><ul><li>Destinado a su empleo en servidores de aplicaci...
Novedades JDBC 4.0 <ul><li>Carga automática de drives JDBC </li></ul><ul><ul><li>Usando el mecanismo de Proveedores de Ser...
Cosas que se quedan en el tintero <ul><li>La configuración y obtención de conexiones vía DataSources JDBC </li></ul><ul><l...
}  finally  {   try  {   if  (presentacion !=  null )    presentacion.close();   }  catch  (SQLException e) {   e.printSta...
Upcoming SlideShare
Loading in...5
×

Jdbc

9,625

Published on

Published in: Technology
0 Comments
3 Likes
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total Views
9,625
On Slideshare
0
From Embeds
0
Number of Embeds
0
Actions
Shares
0
Downloads
535
Comments
0
Likes
3
Embeds 0
No embeds

No notes for slide
  • En realidad JDBC es un nombre comercial por si mismo pero comunmente se conoce por Java Database Connectivity
  • JDBC: Practical Guide for Java Programmers. Gregory Speegle. Morgan Kaufmann, 1st Ed (nov, 2001). ISBN: 1558607366. Malo JDBC API Tutorial and Reference, Third Edition . Maydene Fisher et al. Addison-Wesley Pub Co; 3rd edition (June 11, 2003). ISBN: 0321173848 Guia oficial de sun Java Programming with Oracle JDBC. Donald Bales. O&apos;Reilly (January 2002). ISBN: 0-596-00088-X Bueno. Muchos detalles sobre Oracle. Saca las castañas del fuego en muchas ocasiones. Principles of DB Systems with Internet and Java . G. Riccardi. Addison Wesley 2001. ISBN: 02-0161-247-X Java Oracle Database Development. David J. Gallardo. Prentice Hall PTR (2003). ISBN: 0-13-046218-7 Me gusta. Muy completo. Ubre muchos temas. Un buen libro de programación de BD y no sólo de JDBC JDBC: Practical Guide for Java Programmers. Gregory Speegle. Morgan Kaufmann, 1st Ed (nov, 2001). ISBN: 1558607366. Database Programming with JDBC and Java, 2 nd Edition . George Reese. O&apos;Reilly, 2000. ISBN: 1565926161 Java Database best Practices. George Reese, O’Reilly, 2003. ISBN: 0-596-00522-9 PARA programadores expertos. Trucos consejos sobre como hacer bien y más eficientemente las cosas JDBC™ Guide: Getting Started . Copyright © 1996, 1997, Sun Microsystems, Inc. Documentación sobre JDBC . http://java.sun.com/j2se/1.4.2/docs/guide/jdbc/index.html. PUNTO DE ARRANQUE Oracle9 i JDBC Developer’s Guide and Reference . Copyright © 1999, 2001 Oracle Corporation. COMPLICADA Y MUY DE DETALLE en relación solo con Oracle
  • Razonar xq son interfaces y no clases concretas Ideas ya presentadas en el tema de Panorámica. Incidir en que es una capa entre aplicación y SGBDs Puntualizar: aisla de los detalles de un SBD concreto. Por ejemplo el tema de los comodines lo estandariza (es el % aunque en Access sea el *). Pero hay ciertas cosas que no están bien estandarizadas. Por ejemplo las funciones (son muy dependientes de el SGBD, no igual en Oracle que en Access). Además hay ciertas cosas que no están permitidas por el SGBD pr lo que simplemente no las hace. El metaData informa de si el SGBD soporta o no ciertas características.
  • Decir que la petición de conexión se hace al driver pero que para no ligar la aplicación con un driver concreto (para no tener que recompilar si se cambia luego el SGBD concreto) se hace la petición a un intermediario que elige el driver adecuado y nos devuelve una conexión del tipo adecuado.
  • Repasar los conceptos de conexión-instrucción-cursor del tema de panorámica
  • Repasar de nuevo el q son interfaces. Verlos en el javadoc: decir que hay muy pocas clases concretas y que lo demás (los interfaces) es el resultado del proceso de abstracción de los de sun (los que desarrollaron JDBC) que vieron que elementos había en un API de conxión a BDs Mostrar la lista de drivers (ACTUALIZARLA) http://developers.sun.com/product/jdbc/drivers
  • Los drivers que tiene Orace son de tpo 2 (el OCI) y de tipo 4 (el thin) Para uso con proc almac convene usar el OCI (es más rápido) En el caso de tipo 3: Oracle tiene una cosa llamada ConnectionManaget que actúa como ese middleware (ver Java Programming with Oracle JDBC cap 2 y sec 3.4, 3.4.1)
  • En la página de Sun http://developers.sun.com/product/jdbc/drivers no se listan drivers de tipo 3.
  • Decir que aunque nos referiramos al conjunto de clases que implementan los interfaces JDBC como driver ODBC hay entre esos interface uno que se llama Driver y cuya responsabilidad es dar conexiones Vover a decir que no se usa la clase concreta de driver, xq si lo hacemos perdemos la posibilidad de reutilizar el código con otra BD Si mi código empieza { OracleDriver driver = new OracleDriver(); Connection con = driver.connect(...); Si luego quiero usar el JdbcOdbcDriver, debo entrar en el código, cambiar y luego recompilar.
  • Decir que la petición de conexión se hace al driver pero que para no ligar la aplicación con un driver concreto (para no tener que recompilar si se cambia luego el SGBD concreto) se hace la petición a un intermediario que elige el driver adecuado y nos devuelve una conexión del tipo adecuado.
  • Hemos dicho que el Driverman guarda una lista de los drivers disponibles Como se forma esa lista … Si se desea introducir un nuevo driver después de que el DriverManager se halla inicializado se utilizará el método forname de la clase Class  este método carga ña clase y la clase al cargarse se autoregistra
  • Otras URL para otros drivers de Oracle (ver Java Programming with Oracle JDBC cap 2): Para OCI en Oracle 8: oci8 ... jdbc:oracle:oci8@&lt;nombre tns&gt; Para OCI en Oracle 9: oci ... jdbc:oracle:oci@&lt;nombre tns&gt; Para el driver interno de Oracle: kprb ... ??? Con los OCI sólo se puede usar lo de tns_name y con el thin sólo lo de host:port:sid Hay una direción especial para contactar con la BD local: se trata de dejar en blanco la localización de la BD. Se supone, entonces, que se desea conectar con la BD local: jdbc:oracle:oci@ Mucho ojo! El driver (el classes12.jar) a usar debe ser el correspondiente (exacto) a la versión instalada. Recomiendo copiar el classes12.jar de la carpeta en la que esté como resultado de la instalación y usar ese. Si no puede haber problemas de jaa.lang.UnsatisfiedLinkError en la llamada (ver Java Programming with Oracle JDBC cap 2).
  • Recordar aquí lo de la Breve Intro a la ejec de Statements SQL en la BD que habré tendio que dar antes: alli se introducía el conepto de cursor, … Xej se puede ejecutar stmt.executeUpdate(&amp;quot;begin Insert into mktg values(1000,&apos;xxx&apos;); Insert into mktg values(1001,&apos;yyy&apos;); end;&amp;quot;); Inserta las dos tuplas
  • Y según parece comprobarse aunque se cierre el resultset (cursor), si no se cierra el staement no se cierra definiivamente el cursor. Esto me paso en la aplicación de corregir lo de practicas de sql, que creaba muchos statements (no lo cerraba) en una misma conexión y aunque tuve l cuidado de cerar los resultsets me dio error de demaisados cusores abiertos. Cuando cere el satement no me dio mas el problema
  • Hablar recordar un poco que es la optimización de consultas (referirles a la página web de la asignatura de BD en la que deben estar esos contenidos) y que es el plan de consulta. La sentencia se prepara y luego se ejecuta tantas veces como sea necesario con el plan de ejecución determinado durante la preparación
  • Cada ? Será sustituido por un valor de campo. No vale para nombres de campos ni de tablas. Además al sustituir el valor se aplica el formato adecuado, ej si es varchar, se pone entre ‘’. Esto ayuda a comprender xq esto ESTA MAL String sql = “Select * from articulo where upper(nombre) like upper(‘%?%’)”  al traducir hará … like upper(‘%’ algo’%’) MAL PreparedStatement ps = con.prepareStatement(sql); ps.setString(1,”algo”); Y SI ESTA BIEN String sql = “Select * from articulo where upper(nombre) like upper(?)”  al traducir hará … like upper(‘%algo%’) BIEN PreparedStatement ps = con.prepareStatement(sql); ps.setString(1,”%algo%”); // Es aquí donde ponemos los % Inyecciones de SQL: Ejemplo teclear en el text de un form que pide el nombre de usr lo siguiente admin’ -- y dejar en balnco el de contrseña Si esto se inserta en el siguiente SQL select * from Users where idUsr=‘*’ and pwd=‘**’ Al componer el SQL queda select * from Users where idUsr=‘admin’ --’ and pwd=‘**’ Si el -- es el carácter de comentario esto hace que No se compruiebe la contraseña y se puede entrar en la aplicaicón. EL prepares evita esto xq trata el texto como texto El usar ’12-12-2004’ funciona en Access y en Oracle public class PruFehasAccess { public static void main(String[] args) { String url = &amp;quot;jdbc:odbc:a&amp;quot;; try { Class.forName(&amp;quot;sun.jdbc.odbc.JdbcOdbcDriver&amp;quot;); } catch (ClassNotFoundException e) { System.out.println(&amp;quot;No se ha podido cargar el driver de la JDBC-ODBC&amp;quot;); } Connection con = null; try { con = DriverManager.getConnection(url, &amp;quot;&amp;quot;, &amp;quot;&amp;quot;); Statement select = con.createStatement(); int i = select.executeUpdate(&amp;quot;INSERT INTO a values(&apos;12-12-2003&apos;)&amp;quot;); select.close(); con.close(); } catch (Exception e) { e.printStackTrace(); } finally { try { if (con != null) con.close(); } catch (SQLException ex) { } } } }
  • Criticas al uso de ? Para defenderse del String Interpolation El uso de parámetros posicionales no escala bien: Para dar valor hay que usar la posición y si la query es larga es complicado de entender, tracear … Hay que dar muchos valores y se pierde el control No sirve para todas los casos: &amp;quot;SELECT x, y, z FROM Table WHERE id IN ($set_of_ids)&amp;quot;
  • Cuando se trata de comparaciones no funciona bien y hay que poner el is null. Por ejemplo el código siguiente no funciona a no ser que pongamos lo del is null (no funciona no en Oracle ni en Access): package bd; import util.ResultSetDisplayer; import java.sql.*; public class PruebaPreparedConNull { // Registro del driver apropiado para la BD a utilizar static { try { Class.forName(&amp;quot;sun.jdbc.odbc.JdbcOdbcDriver&amp;quot;); } catch (ClassNotFoundException e) { System.out.println(&amp;quot;No puedo cargar el driver JDBC de la BD&amp;quot;); } } public static void main(String[] args) { try { Connection con = DriverManager.getConnection(&amp;quot;jdbc:odbc:xx&amp;quot;,&amp;quot;&amp;quot;,&amp;quot;&amp;quot;); PreparedStatement ps = con.prepareStatement(&amp;quot;select * from finca where calefacción = ?&amp;quot;); // PreparedStatement ps = con.prepareStatement(&amp;quot;select * from finca where calefacción is null&amp;quot;); Esto si funciona // ps.setString(1, null); ps.setNull(1, Types.VARCHAR); // Es lo mismo que lo de arriba y tp funciona bien ResultSet rs = ps.executeQuery(); ResultSetDisplayer rsd = new ResultSetDisplayer(rs); rsd.print(); rs.close(); ps.close(); con.close(); } catch (SQLException ex) { ex.printStackTrace(); } } }
  • Oracle tiene dos (tres) tipos para fechas, lo de tres es por el Time que sólo almacena hora Aunque esta no existe en Oracle, la tercer es una TIMESTAMP with time zone
  • No dejarse las {} y poner call en minúsculas Si no hay params no se pone (), aunque en Oracle da igual ponerlo que no, en JDBC. Es decir se puede poner {?=call TamanioMedioAlbum} o {?=call TamanioMedioAlbum()} Pero en SQL, no da igual call TamanioMedioAlbum() into :x; FUNCIONA call TamanioMedioAlbum into :x; NO FUNCIONA select TamanioMedioAlbum() from dual; FUNCIONA select TamanioMedioAlbum() from dual; FUNCIONA
  • Ej: se puede contar algo sobre hacer un pedido: el usr mete varias líneas pero se equivoca y en una mete una cantidad negativa. EL sistema lo detecta en forma de restricción de integridad violada. El error debe ser reportado al usr, pues el sistema no sabe como corregirlo (no puede adivinar qué cantidad quería el usr). Pero lo que no puede ser es que quede el pedido a medias de meter (xq no corresponde con ningún pedido real, xq luego se va a intentar de nuevo y estría en parte duplicado, xq el usr se arrepiente y no quiere meterlo).
  • Hay una pequeña diferencia en el comportamiento del nivel de aislamiento serializable en Java y el SQLPlus: Si se abren dos sesiones SQLPlus y se ponen a serializable, en ese momento es como si se hiciese una foto de cómo están las tablas. Si se hace un update+commit en una sesión en la otra el select devolverá el estado pre-update de la tabla alterada en la otra sesion. En java no es del todo así. Si se abren dos conexiones a una BD y se ponen a serializable; si se hace un update+commit en una sesión en la otra el cambio se ve o no dependiendo si hemos empezado ya a hacer cosas: si en la segunda sesión no se ha hecho ningún select se ve el cambio; si ya se ha hecho un select (aunque sea de otra tabla) el cambio no se ve.
  • Cualquier error que puede aparecer en la ejecución normal: deadlock, no serializable, bloqueo no admitido, ... (mostrar la lista inmensa de errores posibles en ORA)
  • Propiedades sobre lo que puede hacer la BD y el driver: procedimientos almacenados, outer joins, … transaciones select for update, savepoints, … Funciones que incluye la BD (to_date, …) y tipos que soporta
  • {escape ‘’} en Oracle es … nombre like ‘\_%’ escape ‘’ y que las secuecnias {d ‘yyyy-mm-dd} no funcioa en SQL directamente Esto hace que la sintaxis de escape sea independiente de la DBMS y permite al programador usar características que de otro modo no estarían disponibles. Los caracteres “%” y “_” trabajan como comodines en la cláusula SQL LIKE (“%” significa cero o más caracteres y “_” significa exactamente un carácter”. En orden a interpretarlos literalmente, pueden estar precedidos por un backslash (‘’), que es un carácter de escape especial en cadenas. Se puede especificar un carácter que se use como carácter de escape por la inclusión de la sintaxis siguiente al final de la consulta. {escape &apos;escape-character&apos;} Por ejemplo, la siguiente consulta, usando backslash como carácter de escape, encuentra nombres de identificador que comiencen con ‘_’. stmt.executeQuery(&amp;quot;SELECT name FROM Identifiers WHERE Id LIKE &apos;\_%&apos; {escape &apos;&apos;};
  • Las conexiones son un recurso limitado: hay que cerrarlas Pero cuando? ¿Tras cada transacción? ¿Se pueden conservar entre transacciones? Depende mucho del tipo de aplicación y de las necesidades se pueden conservar Si hay pocos usr concurrenetes Si hay que mantener las props de transacciones en varias interacciones Pero hay que comprobar que la conexión está viva (y no siempre funciona el isAlive() y hay que hacer queries como SELECT 7 FROM DUAL Hay que cerrarla si hay muchos usrs conectados concurrentemente, por ejemplo en portales (pensar que si la sesión duran 30 m en 30 m pueden entrar miles de usrs). En estos casos tras cada servicio hay que cerrar la conexión. Se suelen usar Pool de conexiones
  • (ver tb http://www.theserverside.com/news/1365244/Why-Prepared-Statements-are-important-and-how-to-use-them-properly ) Ultima opnión de Kyte leída: The use of a Statement in JDBC should be 100% localized to being used for DDL (ALTER, CREATE, GRANT, etc) as these are the only statement types that cannot accept BIND VARIABLES. PreparedStatements or CallableStatements should be used for EVERY OTHER type of statement (DML, Queries). As these are the statement types that accept bind variables. This is a fact, a rule, a law -- use prepared statements EVERYWHERE. Use STATEMENTS almost no where. (ver C:usrFranMasterJDBCAsk-Tom- Statements vs PreparedStatements.doc) Segun Thomas Kyte, SIEMPRE ES MEJOR Prepared que Statement. Exise un bechmark que será el que leí yo en su dñia que decía que sólo era mejor si se repetía muchas veces la query. Pero kyte analiza xq salía ese resulatdo y corrige el test para comprobar que siempre es mejor (ver Effectie Oracle By Design; Oracle Press pág 273). Why Prepared Statements are important and how to use them &amp;quot;properly&amp;quot; Databases have a tough job. They accept SQL queries from many clients concurrently and execute the queries as efficiently as possible against the data. Processing statements can be an expensive operation but databases are now written in such a way so that this overhead is minimized. However, these optimizations need assistance from the application developers if we are to capitalize on them. This article shows you how the correct use of PreparedStatements can significantly help a database perform these optimizations. How does a database execute a statement? Obviously, don&apos;t expect alot of detail here; we&apos;ll only examine the aspects important to this article. When a database receives a statement, the database engine first parses the statement and looks for syntax errors. Once the statement is parsed, the database needs to figure out the most efficient way to execute the statement. This can be computationally quite expensive. The database checks what indexes, if any, can help, or whether it should do a full read of all rows in a table. Databases use statistics on the data to figure out what is the best way. Once the query plan is created then it can be executed by the database engine. It takes CPU power to do the access plan generation. Ideally, if we send the same statement to the database twice, then we&apos;d like the database to reuse the access plan for the first statement. This uses less CPU than if it regenerated the plan a second time. Statement Caches Databases are tuned to do statement caches. They usually include some kind of statement cache. This cache uses the statement itself as a key and the access plan is stored in the cache with the corresponding statement. This allows the database engine to reuse the plans for statements that have been executed previously. For example, if we sent the database a statement such as &amp;quot;select a,b from t where c = 2&amp;quot;, then the computed access plan is cached. If we send the same statement later, the database can reuse the previous access plan, thus saving us CPU power. Note however, that the entire statement is the key. For example, if we later sent the statement &amp;quot;select a,b from t where c = 3&amp;quot;, it would not find an access plan. This is because the &amp;quot;c=3&amp;quot; is different from the cached plan &amp;quot;c=2&amp;quot;. So, for example: for ( int I = 0; I &lt; 1000; ++I) {   PreparedStatement ps = conn.prepareStatement(&amp;quot;select a,b from t where c = &amp;quot; + I);   ResultSet rs = Ps.executeQuery();   Rs.close();   Ps.close(); } Here the cache won&apos;t be used. Each iteration of the loop sends a different SQL statement to the database. A new access plan is computed for each iteration and we&apos;re basically throwing CPU cycles away using this approach. However, look at the next snippet: PreparedStatement ps = conn.prepareStatement(&amp;quot;select a,b from t where c = ?&amp;quot;); for(int I = 0; I &lt; 1000; ++I) {   ps.setInt(1, I);   ResultSet rs = ps.executeQuery();   Rs.close(); } ps.close(); Here it will be much more efficient. The statement sent to the database is parameterized using the &apos;?&apos; marker in the sql. This means every iteration is sending the same statement to the database with different parameters for the &amp;quot;c=?&amp;quot; part. This allows the database to reuse the access plans for the statement and makes the program execute more efficiently inside the database. This basically let&apos;s your application run faster or makes more CPU available to users of the database. PreparedStatements and J2EE servers Things can get more complicated when we use a J2EE server. Normally, a prepared statement is associated with a single database connection. When the connection is closed, the preparedstatement is discarded. Normally, a fat client application would get a database connection and then hold it for its lifetime. It would also create all prepared statements eagerly or lazily. Eagerly means that they are all created at once when the application starts. Lazily means that they are created as they are used. An eager approach gives a delay when the application starts but once it starts then it performs optimally. A lazy approach gives a fast start but as the application runs, the prepared statements are created when they are first used by the application. This gives an uneven performance until all statements are prepared but the application eventually settles and runs as fast as the eager application. Which is best depends on whether you need a fast start or even performance. The problem with a J2EE application is that it can&apos;t work like this. It only keeps a connection for the duration of the request. This means that it must create the prepared statements every time the request is executed. This is not as efficient as the fat client approach where the prepared statements are created once, rather than on every request. J2EE vendors have noticed this and designed connection pooling to avoid this performance disadvantage. When the J2EE server gives your application a connection, it isn&apos;t giving you the actual connection; you&apos;re getting a wrapper. You can verify this by looking at the name of the class for the connection you are given. It won&apos;t be a database JDBC connection, it&apos;ll be a class created by your application server. Normally, if you called close on a connection then the jdbc driver closes the connection. We want the connection to be returned to the pool when close is called by a J2EE application. We do this by making a proxy jdbc connection class that looks like a real connection. It has a reference to the actual connection. When we invoke any method on the connection then the proxy forwards the call to the real connection. But, when we call methods such as close instead of calling close on the real connection, it simply returns the connection to the connection pool and then marks the proxy connection as invalid so that if it is used again by the application we&apos;ll get an exception. Wrapping is very useful as it also helps J2EE application server implementers to add support for prepared statements in a sensible way. When an application calls Connection.prepareStatement, it is returned a PreparedStatement object by the driver. The application then keeps the handle while it has the connection and closes it before it closes the connection when the request finishes. However, after the connection is returned to the pool and later reused by the same, or another application, , then ideally, we want the same PreparedStatement to be returned to the application. J2EE PreparedStatement Cache J2EE PreparedStatement Cache is implemented using a cache inside the J2EE server connection pool manager. The J2EE server keeps a list of prepared statements for each database connection in the pool. When an application calls prepareStatement on a connection, the application server checks if that statement was previously prepared. If it was, the PreparedStatement object will be in the cache and this will be returned to the application. If not, the call is passed to the jdbc driver and the query/preparedstatement object is added in that connections cache. We need a cache per connection because that&apos;s the way jdbc drivers work. Any preparedstatements returned are specific to that connection. If we want to take advantage of this cache, the same rules apply as before. We need to use parameterized queries so that they will match ones already prepared in the cache. Most application servers will allow you to tune the size of this prepared statement cache. Comentarios del documento de consultoria de reingeniería de Saunier Duval (pueden estar obsoletos – HAY ERRORES según Thomas Kyte (ver coemntario de arriba)) Sobre el uso de PreparedStatement en vez de Statements El API Java para acceso a bases de datos (JDBC) proporciona dos instrumentos para la realización de consultas y actualizaciones: Statement y PreparedStatement. El propósito del segundo es optimizar la ejecución de la operación. Para ello el driver accede una vez a la BD para recuperar los metadatos asociados a la consulta (tipos, estructuras de tablas, …) y los reutiliza en posteriores accesos. En contraposición, un Statement hace dos accesos a la BD cada vez: uno para recuperar los metadatos asociados a la operación, y otro para ejecutarla. Podría pensarse, por tanto, que usar un PreparedStatement siempre será más eficiente que emplear su correspondiente Statement. Sin embargo los datos experimentales no demuestran tal cosa: En primer lugar es preciso aclarar que casi todos los gestores de base de datos realizan un cacheo interno de las consultas (selects) que procesan, almacenando el plan de ejecución para posteriores reutilizaciones. El efecto de PreparedStatement en consultas se ve superado por esta optimización a nivel de SGBD, por lo que su empleo se ha de limitar a el caso de consultas de actualización (insert, update, delete). Un objeto PreparedStatement está vinculado a la conexión JDBC que lo crea, por lo que, si se cambia de conexión, se debe crear y recompilar de nuevo, eliminándose, evidentemente, el efecto de la optimización. A pesar de que pudiera parecer que a partir de la segunda ejecución, y posteriores, un PreparedStatement es al menos un 50 % más rápido que un Statement, experimentalmente es posible comprobar que el rendimiento de PreparedStatement no es superior al de Statement hasta que al consulta no se repite unas 125 veces( Utilizando el Thin driver de Oracle, sobre base de datos Oracle 8.1.6) . La sobrecarga de utilización de un objeto PreparedStatement (el tiempo de preparación de la operación es siginificativamente más grande que el de la correspondiente Statement) explica este comportamiento. Ya que cada PreparedStatement está asociado con cada conexión, que en el portal se utiliza un pool de conexiones (de tamaño mínimo 10), que, para sacar partido de la optimización, es preciso repetir la ejecución de cada PreparedStatement más de 100 veces, que las conexiones en el pool son destruidas periódicamente para evitar problemas de obsolescencia, y que las consultas que se pueden optimizar (actualizaciones) son menos habituales, se deduce que es muy difícil garantizar una mejora en el rendimiento imputable al uso de PreparedStatement. Si a lo anterior añadimos la consideración del sobre-coste de diseño y codificación que implica el empleo de este tipo de objetos JDBC
  • SOLO vale para Statement. Si se prueba a hacer con PreparedStatement fall (método no soportado). Al menos en Oracle. SI no se dice nada no es transacional. Es decir cada instrucción del lote se autoconfirma. Se puede comprobar con el siguiente codigo (en el que se hace fallar al lote al incluir un dato que viola una restricción). Se comprueba que los datos anteriores si están en la BD (si se hace un setAutocomit false ya no estárán los datos): import bd.ConnectionManager; import java.sql.Connection; import java.sql.*; public class PruBatch { public static void main(String[] args) { initBD(); añadeDatos(); } private static void initBD() { Connection con = null; try { con = ConnectionManager.getConnection(); Statement stm = con.createStatement(); stm.addBatch(&amp;quot;drop table AAAA cascade constraints&amp;quot;); stm.addBatch(&amp;quot;create table AAAA (a Number(1,0) check (a&gt;0))&amp;quot;); stm.executeBatch(); stm.close(); } catch (SQLException ex) { ex.printStackTrace(); } finally { if (con != null) { try { ConnectionManager.returnConnection(con); } catch (SQLException ex1) { ex1.printStackTrace(); } } } } private static void añadeDatos() { Connection con = null; try { con = ConnectionManager.getConnection(); Statement stm = con.createStatement(); stm.addBatch(&amp;quot;insert into AAAA values (1)&amp;quot;); stm.addBatch(&amp;quot;insert into AAAA values (2)&amp;quot;); stm.addBatch(&amp;quot;insert into AAAA values (3)&amp;quot;); stm.addBatch(&amp;quot;insert into AAAA values (-4)&amp;quot;); stm.addBatch(&amp;quot;insert into AAAA values (5)&amp;quot;); stm.executeBatch(); stm.close(); } catch (SQLException ex) { ex.printStackTrace(); } finally { if (con != null) { try { ConnectionManager.returnConnection(con); } catch (SQLException ex1) { ex1.printStackTrace(); } } } } }
  • ResultSet.TYPE_SCROLL_INSENSITIVE , una vez consultados los datos si estos son cambiados por terceros no veremos los cambios. Los cambios no se sincronizan De esto habla un poco el libro “Databases and Transaction Processing”, pág 305. Scroll insensitive : Usa un cursor INSENSITIVE supone que una vez hecha la consulta los cambios realizados en las tablas subyacentes a la consulta por otros usuarios, transacciones, sesiones (como quiera verse) o por la misma transacción que creo el resultset (que puede, tras consultar el resultset, hacer cambios en la stablas y seguir teniendo el result set a medias de procesar), que esos cambios no son visibles por el result set Scroll sensitive: usa un Cursor SENSITIVE. SQL standard no define un comportamiento esperado cunado la opción INSENSITIVE. Los abricantes de SGBD pueden hacer lo que quieran y JDBC lo que hace es proporcionar la semántica del SGBD subyacente. Muchos usan lo que se denomina semantica KEYSET_DRIVEN, por la cual los updates y deleets son visibles pero los inserts no. Para actualizar hay una serir de métodos update&lt;Tipo&gt; y luego se hace updateRow(). Tambien se puede hacer insertRow() para añadir una fila vacía y luego grabarla con updateRow. El control de la concurrencia los cambios he leido que se hace con locks de escritura, de modo que solo un cada vez puede tener el resultset; otras implementacione spueden usar estrategias optimistas. Ej: con.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_UPDATABLE );   Luego, para cambiar los datos se usan métodos updateXxx(). Por ejemplo:   ResultSet rs = stmt.executeQuery(&amp;quot;SELECT * FROM Cosa&amp;quot;); while (rs.next()) { if ( true ) { double delta = 8; double precio = rs.getDouble(&amp;quot;Precio&amp;quot;); rs. updateDouble (&amp;quot;Precio&amp;quot;, precio+delta); rs. updateRow (); }
  • Incluso en drivers que si las soportan, determinadas queries complejas pueden devolver resultados que por ejemplo no sean modificables : supongo (eso es mio) que pasará algo parecido a lo que sucede con las vistas; habrá resultados que no se puedan actualizar: uniones, groups, ...
  • JDBC 3 incluye cosas sobre (ver tb http://www.ibm.com/developerworks/java/library/j-jdbcnew/): - conexiones: parametros standard - cacheo/pooling de prepared statements - parámetros con nombre (no solo posición) en CallableStatements - resultset que no se cierran al hacer commit en la conexión (resultSet holdability) - se pueden tener abiertos a la vez en instrucciones que devuelvan varios resultsets - Se pueden recuperar los valores autogenerados que se suelen usar en campos clave (en SGBD que lo permitan, claro; Oracle lo dudo) - mejoras en resultset para poder get y set tipos CLOB BLOB y ARRAY
  • The DriverManager.getConnection method has been enhanced to support the Java Standard Edition Service Provider mechanism. JDBC 4.0 Drivers must include the file META-INF/services/java.sql.Driver. This file contains the name of the JDBC driver’s implementation of java.sql.Driver.
  • Interrogación didáctica – evaluación formativa Cuál es el proceso de trabajo con JDBC? (cargar driver, abrir conexión, statem, procesar, cerrar) ¿Cómo se procesa un ResultSet? (next y getXXX) ¿Hay que cerrar el ResultSet? ¿Hay que cerrar la conexión? Hemos dicho “La aplicación no suele trabajar directamente con el Driver concreto”. ¿Qué pasaría si trabajasemos con un driver concreto en una determinada aplicación (falta de genericidad)? ¿Qué hay que hacer para que una aplicación construida con JDBC cambie la BD sobre la qe trabaja (cambiar los params de conexión) Cosas a mandar: Lectura/escritura de CLOBS CachedRowSet
  • Transcript of "Jdbc"

    1. 1. JDBC Java Database Connectivity
    2. 2. Bibliografía <ul><li>JDBC API Tutorial and Reference, Third Edition . Maydene Fisher et al. Addison-Wesley Pub Co; 3rd edition (June 11, 2003). ISBN: 0321173848 </li></ul><ul><li>Java Programming with Oracle JDBC. Donald Bales. O'Reilly (January 2002). ISBN: 0-596-00088-X </li></ul><ul><li>Principles of DB Systems with Internet and Java . G. Riccardi. Addison Wesley 2001. ISBN: 02-0161-247-X </li></ul><ul><li>Java Oracle Database Development. David J. Gallardo. Prentice Hall PTR (2003). ISBN: 0-13-046218-7 </li></ul><ul><li>JDBC: Practical Guide for Java Programmers. Gregory Speegle. Morgan Kaufmann, 1st Ed (nov, 2001). ISBN: 1558607366. </li></ul><ul><li>Database Programming with JDBC and Java, 2 nd Edition . George Reese. O'Reilly, 2000. ISBN: 1565926161 </li></ul><ul><li>Java Database best Practices. George Reese, O’Reilly, 2003. ISBN: 0-596-00522-9 </li></ul><ul><li>JDBC™ Guide: Getting Started . Copyright © 1996, 1997, Sun Microsystems, Inc. </li></ul><ul><li>Documentación sobre JDBC . http://java.sun.com/j2se/1.4.2/docs/guide/jdbc/index.html. </li></ul><ul><li>Oracle9 i JDBC Developer’s Guide and Reference . Copyright © 1999, 2001 Oracle Corporation. </li></ul><ul><li>Effective Oracle by design . Thomas Kyte. Oracle Press, 2003. ISBN: 0-07-223065-7 </li></ul>  
    3. 3. Objetivos <ul><li>Profundizar en la estrategia de programación CLI, particularizando para Java </li></ul><ul><ul><li>Conocer la estructura habitual de las librerías CLI a través del caso particular de Java </li></ul></ul><ul><li>Conocer el lugar de JDBC en la arquitectura de las aplicaciones con acceso a BD </li></ul><ul><li>Evaluar las ventajas del uso de un API estándar de acceso a BD </li></ul><ul><li>Dominar el proceso de trabajo con JDBC </li></ul><ul><li>Dominar en un 50% el API JDBC </li></ul><ul><ul><li>Ser capaz de conectar con BD remotas </li></ul></ul><ul><ul><li>Ser capaz de realizar consultas y actualizaciones sobre una BD remota </li></ul></ul><ul><ul><li>Ser capaz de recabar información sobre la BD remota </li></ul></ul><ul><ul><li>Ser capaz de gestionar la transaccionalidad en JDBC </li></ul></ul><ul><li>Conocer las aportaciones de las nuevas especificaciones JDBC 2 y 3 </li></ul>
    4. 4. Agenda <ul><li>Introducción </li></ul><ul><li>Drivers JDBC </li></ul><ul><li>La clase DriverManager </li></ul><ul><li>Conexiones </li></ul><ul><li>Ejecución de instrucciones </li></ul><ul><li>Transacciones y SQL </li></ul><ul><li>Cuando las cosas van mal </li></ul><ul><li>Temas avanzados </li></ul><ul><li>JDBC 2 </li></ul><ul><li>Introducción </li></ul><ul><li>Drivers JDBC </li></ul><ul><li>La clase DriverManager </li></ul><ul><li>Conexiones </li></ul><ul><li>Ejecución de instrucciones </li></ul><ul><li>Transacciones y SQL </li></ul><ul><li>Cuando las cosas van mal </li></ul><ul><li>Temas avanzados </li></ul><ul><li>JDBC 2 </li></ul>
    5. 5. Introducción <ul><li>JDBC es un conjunto de clases e interfaces Java para la ejecución de sentencias SQL ( ver JavaDoc ). </li></ul><ul><li>Es el CLI de Java </li></ul><ul><li>Ha sido desarrollado conjuntamente por JavaSoft, Sybase, Informix, e IBM entre otros. </li></ul><ul><li>JDBC permite manipular cualquier base de datos SQL. No es necesario hacer un programa para manipular Oracle, otro para Sybase, etc... Un mismo programa puede manipular cualquier base de datos. </li></ul><ul><li>Uniendo Java con JDBC tenemos programas que se pueden ejecutar en cualquier plataforma y que pueden manipular cualquier base de datos. </li></ul><ul><li>Las clases e interfaces JDBC se encuentran en el paquete java.sql . </li></ul>
    6. 6. Proceso de trabajo con JDBC Aplicación JDBC Driver A Connection Statement Gestor de drivers Driver B ResultSet  getConnection  createStatement  executeQuery
    7. 7. <ul><li>El proceso de trabajo en JDBC consiste en: </li></ul><ul><ul><li>Conectarse a la base de datos ( DriverManager ). </li></ul></ul><ul><ul><li>Emitir sentencias SQL ( Statement , PreparedStatement , CallableStatement ). </li></ul></ul><ul><ul><li>Procesar los resultados ( ResulSet ). </li></ul></ul><ul><li>Ejemplo: </li></ul><ul><ul><li>Connection con = DriverManager.getConnection( &quot;jdbc:odbc:misdatos&quot;, &quot;login&quot;, &quot;password&quot;); </li></ul></ul><ul><ul><li>Statement stmt = con.createStatement(); </li></ul></ul><ul><ul><li>ResultSet rs = stmt.executeQuery(&quot;SELECT d1, d2, d3 FROM Tabla1&quot;); </li></ul></ul><ul><ul><li>while (rs.next()) { </li></ul></ul><ul><ul><li>int x = getInt(”d1&quot;); </li></ul></ul><ul><ul><li>String s = getString(”d2&quot;); </li></ul></ul><ul><ul><li>float f = getFloat(”d3&quot;); </li></ul></ul><ul><ul><li>} </li></ul></ul>Proceso de trabajo con JDBC Connection con = DriverManager.getConnection( &quot;jdbc:odbc:misdatos&quot;, &quot;login&quot;, &quot;password&quot;); Statement stmt = con.createStatement(); ResultSet rs = stmt.executeQuery(&quot;SELECT d1, d2, d3 FROM Tabla1&quot;); while (rs.next()) { int x = rs.getInt(”d1&quot;); String s = rs.getString(”d2&quot;); float f = rs.getFloat(”d3&quot;); } <ul><li>El proceso de trabajo en JDBC consiste en: </li></ul><ul><ul><li>Conectarse a la base de datos ( DriverManager ). </li></ul></ul><ul><ul><li>Emitir sentencias SQL ( Statement , PreparedStatement , CallableStatement ). </li></ul></ul><ul><ul><li>Procesar los resultados ( ResulSet ). </li></ul></ul><ul><li>Ejemplo: </li></ul><ul><ul><li>Connection con = DriverManager.getConnection( &quot;jdbc:odbc:misdatos&quot;, &quot;login&quot;, &quot;password&quot;); </li></ul></ul><ul><ul><li>Statement stmt = con.createStatement(); </li></ul></ul><ul><ul><li>ResultSet rs = stmt.executeQuery(&quot;SELECT d1, d2, d3 FROM Tabla1&quot;); </li></ul></ul><ul><ul><li>while (rs.next()) { </li></ul></ul><ul><ul><li>int x = getInt(”d1&quot;); </li></ul></ul><ul><ul><li>String s = getString(”d2&quot;); </li></ul></ul><ul><ul><li>float f = getFloat(”d3&quot;); </li></ul></ul><ul><ul><li>} </li></ul></ul>Connection con = DriverManager.getConnection( &quot;jdbc:odbc:misdatos&quot;, &quot;login&quot;, &quot;password&quot;); Statement stmt = con.createStatement(); ResultSet rs = stmt.executeQuery(&quot;SELECT d1, d2, d3 FROM Tabla1&quot;); while (rs.next()) { int x = rs.getInt(”d1&quot;); String s = rs.getString(”d2&quot;); float f = rs.getFloat(”d3&quot;); } <ul><li>El proceso de trabajo en JDBC consiste en: </li></ul><ul><ul><li>Conectarse a la base de datos ( DriverManager ). </li></ul></ul><ul><ul><li>Emitir sentencias SQL ( Statement , PreparedStatement , CallableStatement ). </li></ul></ul><ul><ul><li>Procesar los resultados ( ResulSet ). </li></ul></ul><ul><li>Ejemplo: </li></ul><ul><ul><li>Connection con = DriverManager.getConnection( &quot;jdbc:odbc:misdatos&quot;, &quot;login&quot;, &quot;password&quot;); </li></ul></ul><ul><ul><li>Statement stmt = con.createStatement(); </li></ul></ul><ul><ul><li>ResultSet rs = stmt.executeQuery(&quot;SELECT d1, d2, d3 FROM Tabla1&quot;); </li></ul></ul><ul><ul><li>while (rs.next()) { </li></ul></ul><ul><ul><li>int x = getInt(”d1&quot;); </li></ul></ul><ul><ul><li>String s = getString(”d2&quot;); </li></ul></ul><ul><ul><li>float f = getFloat(”d3&quot;); </li></ul></ul><ul><ul><li>} </li></ul></ul>Connection con = DriverManager.getConnection( &quot;jdbc:odbc:misdatos&quot;, &quot;login&quot;, &quot;password&quot;); Statement stmt = con.createStatement(); ResultSet rs = stmt.executeQuery(&quot;SELECT d1, d2, d3 FROM Tabla1&quot;); while (rs.next()) { int x = rs.getInt(”d1&quot;); String s = rs.getString(”d2&quot;); float f = rs.getFloat(”d3&quot;); } <ul><li>El proceso de trabajo en JDBC consiste en: </li></ul><ul><ul><li>Conectarse a la base de datos ( DriverManager ). </li></ul></ul><ul><ul><li>Emitir sentencias SQL ( Statement , PreparedStatement , CallableStatement ). </li></ul></ul><ul><ul><li>Procesar los resultados ( ResulSet ). </li></ul></ul><ul><li>Ejemplo: </li></ul><ul><ul><li>Connection con = DriverManager.getConnection( &quot;jdbc:odbc:misdatos&quot;, &quot;login&quot;, &quot;password&quot;); </li></ul></ul><ul><ul><li>Statement stmt = con.createStatement(); </li></ul></ul><ul><ul><li>ResultSet rs = stmt.executeQuery(&quot;SELECT d1, d2, d3 FROM Tabla1&quot;); </li></ul></ul><ul><ul><li>while (rs.next()) { </li></ul></ul><ul><ul><li>int x = getInt(”d1&quot;); </li></ul></ul><ul><ul><li>String s = getString(”d2&quot;); </li></ul></ul><ul><ul><li>float f = getFloat(”d3&quot;); </li></ul></ul><ul><ul><li>} </li></ul></ul>Connection con = DriverManager.getConnection( &quot;jdbc:odbc:misdatos&quot;, &quot;login&quot;, &quot;password&quot;); Statement stmt = con.createStatement(); ResultSet rs = stmt.executeQuery(&quot;SELECT d1, d2, d3 FROM Tabla1&quot;); while (rs.next()) { int x = rs.getInt(”d1&quot;); String s = rs.getString(”d2&quot;); float f = rs.getFloat(”d3&quot;); }
    8. 8. Agenda <ul><li>Introducción </li></ul><ul><li>Drivers JDBC </li></ul><ul><li>La clase DriverManager </li></ul><ul><li>Conexiones </li></ul><ul><li>Ejecución de instrucciones </li></ul><ul><li>Transacciones y SQL </li></ul><ul><li>Cuando las cosas van mal </li></ul><ul><li>Temas avanzados </li></ul><ul><li>JDBC 2 </li></ul>
    9. 9. El driver JDBC <ul><li>JDBC es básicamente una colección de interfaces Java (paquete java.sql ). P.ej. </li></ul><ul><ul><li>Connection </li></ul></ul><ul><ul><li>Statement </li></ul></ul><ul><ul><li>ResultSet </li></ul></ul><ul><li>Cada BD concreta implementará los interfaces de una manera particular </li></ul><ul><ul><li>La conexión ( Connection ) con Oracle no se hace igual que la conexión con Access </li></ul></ul><ul><li>Para una BD concreta, el conjunto de clases implementación, clases auxiliares y clases de utilidad componen el driver JDBC para esa BD </li></ul><ul><li>Una misma aplicación puede conectar con distintas BD con sólo cambiar el driver </li></ul>
    10. 10. Tipos de drivers <ul><li>Tipo 1: Puente JDBC-ODBC </li></ul><ul><ul><li>Traduce JDBC a ODBC y lo retransmite al driver ODBC de la máquina </li></ul></ul><ul><ul><li>Es el driver ODBC el que realmente comunica con la BD </li></ul></ul><ul><ul><li>Se suministra con la JDK pero no incluye JDBC2 </li></ul></ul><ul><ul><li>Pegas </li></ul></ul><ul><ul><ul><li>Puede ser útil para pruebas pero es lento en producción </li></ul></ul></ul><ul><ul><ul><li>Necesita del driver ODBC en cliente (menor portabilidad) </li></ul></ul></ul><ul><li>Tipo 2: Driver JDBC sobre driver nativo de la BD </li></ul><ul><ul><li>Retransmite JDBC al driver nativo instalado en la máquina </li></ul></ul><ul><ul><li>Es el driver nativo el que realmente se comunica con la BD </li></ul></ul><ul><ul><li>Precisa de instalación de driver nativo (menor portabilidad) </li></ul></ul>
    11. 11. Tipos de drivers (II) <ul><li>Tipo 3: Driver Java sobre red </li></ul><ul><ul><li>Traduce las llamadas JDBC a un protocolo de red independiente de la plataforma que contacta con el servidor </li></ul></ul><ul><ul><li>El servidor traduce esas peticiones al protocolo concreto de cada BD </li></ul></ul><ul><ul><li>Usa middleware en el servidor de red que es capaz de conectar a los clientes puros Java a muchas bases de datos diferentes </li></ul></ul><ul><ul><li>Rápido, independiente de la plataforma y no requiere de instalación en el cliente </li></ul></ul><ul><li>Tipo 4: Driver puro Java con protocolo nativo </li></ul><ul><ul><li>Traduce las JDBC al protocolo específico de la BD </li></ul></ul><ul><ul><li>Y contacta directamente con ella </li></ul></ul>
    12. 12. Tipos de drivers (III) Driver ODBC
    13. 13. El interface Driver y la clase DriverManager <ul><li>El interface Driver especifica los métodos que todo driver JDBC debe implementar. </li></ul><ul><li>Será necesario un driver por cada tipo de base de datos que se desee utilizar (un driver para Oracle, otro para MySQL, etc...) y será el encargado de abrir conexiones con las mismas ( Connection ). </li></ul><ul><li>Ejemplos de drivers </li></ul><ul><ul><li>sun.jdbc.odbc.JdbcOdbcDriver </li></ul></ul><ul><ul><li>oracle.jdbc.driver.OracleDriver </li></ul></ul><ul><ul><li>com.microsoft.jdbc.sqlserver.SQLServerDriver </li></ul></ul><ul><ul><li>com.mysql.jdbc.Driver </li></ul></ul><ul><li>No se suele trabajar directamente con la clase concreta. </li></ul><ul><li>El DriverManager agrupa los drivers y es el encargado de entregar el Driver adecuado para cada base de datos. </li></ul>
    14. 14. Agenda <ul><li>Introducción </li></ul><ul><li>Drivers JDBC </li></ul><ul><li>La clase DriverManager </li></ul><ul><li>Conexiones </li></ul><ul><li>Ejecución de instrucciones </li></ul><ul><li>Transacciones y SQL </li></ul><ul><li>Cuando las cosas van mal </li></ul><ul><li>Temas avanzados </li></ul><ul><li>JDBC 2 </li></ul>
    15. 15. Clase DriverManager <ul><li>Es la capa de gestión de JDBC </li></ul><ul><li>Se sitúa entre la aplicación que usará JDBC y los drivers JDBC de la BD </li></ul><ul><li>Guarda una lista de los drivers disponibles y … </li></ul><ul><li>… establece la conexión entre la BD y el driver apropiado para cada aplicación </li></ul><ul><li>Es la primera clase JDBC con la que las aplicaciones contactan para comenzar una conexión JDBC </li></ul><ul><ul><li>DriverManager.getConnection(...) </li></ul></ul>
    16. 16. Proceso de trabajo con JDBC Aplicación JDBC Driver A Connection Statement Gestor de drivers Driver B ResultSet  getConnection  createStatement  executeQuery
    17. 17. Mantenimiento de la lista de drivers <ul><li>¿Cómo se forma la lista de drivers disponibles? </li></ul><ul><li>Toda clase Driver debe auto-registrarse en el Drivermanager nada más cargarse </li></ul><ul><li>Una clase Driver se carga, y por tanto se registra, de dos formas diferentes: </li></ul><ul><ul><li>Cuando se inicia, el DriverManager consulta la propiedad jdbc.drivers . Dicha propiedad contiene una lista de drivers (las clases) que se desea cargar. </li></ul></ul><ul><ul><li>Si se desea introducir un nuevo driver después de que el DriverManager se haya inicializado se utilizará el método forName de la clase Class </li></ul></ul>> java -Djdbc.drivers= sun.jdbc.odbc.JdbcOdbcDriver aplicación Class.forName(&quot;sun.jdbc.odbc.JdbcOdbcDriver&quot;);
    18. 18. Dónde poner el forName <ul><li>El driver se debe registrar una única vez durante la vida de la aplicación </li></ul><ul><li>Se debe registrar al iniciar la aplicación (antes de pedir una conexión) </li></ul><ul><li>Se debe elegir una clase que se inicialice al arrancar la aplicación y … </li></ul><ul><li>… usar un bloque static para cargar el driver </li></ul>public class GestorBD { static { try { Class.forName(&quot;oracle.jdbc.driver.OracleDriver&quot;); } catch (ClassNotFoundException e) { System.out.println(&quot;No se ha podido cargar el driver de laBD&quot;); } } ... Resto de la clase }
    19. 19. Obtención de conexiones <ul><li>Es el Driver concreto el que realiza las conexiones, pero las solicitudes de conexión se realizan al DriverManager </li></ul><ul><li>Una vez que la clase Driver ha sido cargada y registrada en DriverManager , se pueden establecer conexiones con la BD. </li></ul><ul><ul><li>Llamada al método DriverManager.getConnection(…) </li></ul></ul><ul><ul><li>el DriverManager prueba los drivers registrados para ver si puede establecer la conexión. </li></ul></ul><ul><ul><li>Para ello usa la URL de conexión </li></ul></ul><ul><li>Ejemplo (para Oracle) </li></ul>Class.forName(&quot; oracle.jdbc.driver.OracleDriver &quot;); String url = &quot;jdbc:oracle:thin:@localhost:1521:PBD&quot;; Connection con = DriverManager.getConnection(url, &quot;PBD&quot;, &quot;pbdpbd&quot;);
    20. 20. Agenda <ul><li>Introducción </li></ul><ul><li>Drivers JDBC </li></ul><ul><li>La clase DriverManager </li></ul><ul><li>Conexiones </li></ul><ul><li>Ejecución de instrucciones </li></ul><ul><li>Transacciones y SQL </li></ul><ul><li>Cuando las cosas van mal </li></ul><ul><li>Temas avanzados </li></ul><ul><li>JDBC 2 </li></ul>
    21. 21. El interface Connection <ul><li>Un objeto de tipo Connection representa una sesión abierta con una base de datos. </li></ul><ul><li>Provee de un contexto en el que emitir sentencias SQL y obtener resultados. </li></ul><ul><li>Una aplicación puede tener varias conexiones a una misma base de datos y/o varias conexiones a distintas bases de datos. </li></ul><ul><li>A partir de una conexión se puede: </li></ul><ul><ul><li>Obtener objetos Statement , PreparedStatement o CallableStatement para ejecutar sentencias SQL. </li></ul></ul><ul><ul><li>Establecer el modo de las transacciones. </li></ul></ul><ul><ul><li>Obtener información sobre la base de datos ( DatabaseMetadata ). </li></ul></ul><ul><li>Las conexiones se obtienen del DriverManager mediante el método getConnection. </li></ul>
    22. 22. URLs en JDBC <ul><li>Uno de los parámetros del método getConnection indica la URL (con protocolo jdbc ) que permite localizar la BD. </li></ul><ul><li>La forma general de esta URL es: </li></ul><ul><ul><li>jdbc:<subprotocolo>:<subnombre> </li></ul></ul><ul><li>Por ejemplo: </li></ul><ul><ul><li>jdbc:oracle:thin:@172.77.77.77:1521:MIBD </li></ul></ul><ul><ul><li>jdbc:odbc:MiBD </li></ul></ul><ul><li>El subprotocolo es particular de cada SGBD y lo utiliza el DriverManager para buscar el Driver adecuado para manipular la base de datos </li></ul><ul><li>El formato subnombre depende de cada subprotocolo concreto. El Driver será el encargado de interpretarlo y le ayudará a localizar de alguna manera la base de datos. </li></ul><ul><li>Los otros parámetros de getConnection son el nombre de usuario y la contraseña </li></ul>
    23. 23. Ejemplo de código de conexión a Oracle try { Class.forName(&quot;oracle.jdbc.driver.OracleDriver&quot;); } catch (ClassNotFoundException e) { System.err.println(&quot;No se ha podido cargar el driver de la BD&quot;); } ... Connection con = null ; try { String url = &quot;jdbc:oracle:thin:@localhost:1521:PBD&quot;; con = DriverManager.getConnection(url, &quot;PBD&quot;, &quot;pbdpbd&quot;); ... Trabajo con la conexión } catch (SQLException e) { e.printStackTrace(); } finally { try { if (con != null ) con.close(); } catch (SQLException e2) { e2.printStackTrace(); } }
    24. 24. Importante <ul><li>La aplicación no suele trabajar directamente con el Driver concreto. </li></ul><ul><li>Le pide al DriverManager conexiones a la BD concreta </li></ul><ul><li>Busca por su lista de drivers alguno que sepa tratar el tipo de URL especificada y devuelve un objeto Connection (genérico) </li></ul><ul><li>De esta manera las aplicaciones trabajan con Connection s sin preocuparse del tipo de base de datos con la que trabajan. </li></ul><ul><li>El mismo código sirve para cualquier BD. Sólo hay que cambiar la URL. </li></ul><ul><li>IMPORTANTÍSIMO: cerrar la conexión . Usar el bloque finally </li></ul>
    25. 26. Agenda <ul><li>Introducción </li></ul><ul><li>Drivers JDBC </li></ul><ul><li>La clase DriverManager </li></ul><ul><li>Conexiones </li></ul><ul><li>Ejecución de instrucciones </li></ul><ul><li>Transacciones y SQL </li></ul><ul><li>Cuando las cosas van mal </li></ul><ul><li>Temas avanzados </li></ul><ul><li>JDBC 2 </li></ul>
    26. 27. El interface Statement <ul><li>Los objetos Statement permiten la ejecución de sentencias SQL y obtener los resultados. </li></ul><ul><li>Es la propia conexión la que actúa como factoría de Statements: </li></ul><ul><ul><li>Connection.createStatement() </li></ul></ul><ul><li>Básicamente hay dos formas de lanzar sentencias SQL: </li></ul><ul><ul><li>Método executeQuery(<sql>) para comandos SQL que producen tuplas como resultado (consultas SELECT) </li></ul></ul><ul><ul><ul><ul><li>ResultSet rs = stmt.executeQuery(&quot;SELECT a, b, c FROM Table2&quot;); </li></ul></ul></ul></ul><ul><ul><li>Método executeUpdate(<sql>) en sentencias INSERT, DELETE, UPDATE, comandos DDL (CREATE, DROP, etc...) y bloques PL/SQL (entre begin y end;). </li></ul></ul><ul><ul><ul><ul><li>stmt.executeUpdate(”DROP TABLE Table2&quot;); </li></ul></ul></ul></ul>Connection con = DriverManager.getConnection(url, usr, pwd); Statement stmt = con. createStatement() ; ResultSet rs = stmt.executeQuery(&quot;SELECT a, b, c FROM Table2&quot;); stmt.executeUpdate(&quot;DROP TABLE Table2&quot;); int n = stmt.executeUpdate(&quot;UPDATE Table2 SET a = a + 1&quot;);
    27. 28. El interface Statement (II) <ul><li>El Método executeQuery devuelve un objeto de tipo ResultSet </li></ul><ul><ul><li>Es como una tabla que almacena el resultado de la consulta </li></ul></ul><ul><ul><li>Tiene una serie de métodos de consulta </li></ul></ul><ul><ul><li>Es como un cursor (en terminología PL/SQL) </li></ul></ul><ul><li>El método executeUpdate devuelve un entero que indica el número de filas modificadas por el comando </li></ul><ul><ul><li>Y en comandos DDL (CREATE, DROP, etc...) devuelve 0 </li></ul></ul><ul><li>Hay un método execute( <sql> ) que ejecuta cualquier tipo de sentencia </li></ul><ul><ul><li>Si es un SELECT devolverá true </li></ul></ul><ul><ul><ul><li>El ResultSet se deberá conseguir con getResultSet() </li></ul></ul></ul><ul><ul><li>Si es un UPDATE, …, devolverá false </li></ul></ul><ul><ul><ul><li>Las filas modificadas se consiguen con getUpdateCount() </li></ul></ul></ul>
    28. 29. El interface Statement (III) <ul><li>Una vez que el resultado haya sido procesado se debe cerrar el Statement mediante el método close() . </li></ul><ul><ul><li>Esto cierra también el ResultSet asociado </li></ul></ul><ul><ul><li>Aun así Sun recomienda CERRAR EL ResultSet EXPLICITAMENTE </li></ul></ul><ul><li>Un mismo Statement puede reutilizarse en una misma conexión para ejecutar distintas sentencias. </li></ul><ul><ul><li>Al reejecutar un Statement se cierran los ResultSet anteriores </li></ul></ul><ul><ul><li>Aun así Sun recomienda CERRAR EL ResultSet EXPLICITAMENTE </li></ul></ul>
    29. 30. Ejemplo de código para Oracle // Carga del driver (Class.forName ... Connection con = null ; try { String url = &quot;jdbc:oracle:thin:@localhost:1521:PBD&quot;; con = DriverManager.getConnection(url, &quot;PBD&quot;, &quot;pbdpbd&quot;); Statement stmt = con.createStatement(); ResultSet rs = stmt.executeQuery(“SELECT a, b, c FROM Table2&quot;); ... Procesamiento del resultado rs.close(); stmt.close(); } catch (SQLException e) { e.printStackTrace(); } finally { try { if (con != null ) con.close(); } catch (SQLException e2) { e2.printStackTrace(); } } OJO QUE NO ACABE EN ;
    30. 31. Composición del SQL <ul><li>El SQL que aceptan los métodos executeXxx es un String (JDBC es CLI) </li></ul><ul><li>Puede componerse dinámicamente en función de valores de variables </li></ul><ul><li>Para componer el String del SQL habrá que concatenar los distintos trozos del SQL (los estáticos y los variables). </li></ul>String id = &quot;xx67yw8“; String sql = &quot; SELECT a, b, c FROM Table2 WHERE id =' &quot; + id + &quot; ' &quot; ; ResultSet rs = stmt.executeQuery(sql);
    31. 32. El interface ResultSet <ul><li>Los objetos de tipo ResultSet ofrecen métodos para recorrer el resultado de una consulta. </li></ul><ul><li>Mantiene un puntero a la fila actual. </li></ul><ul><ul><li>Cada vez que se invoca el método next() se pasa a la siguiente fila. </li></ul></ul><ul><ul><li>Inicialmente el puntero se sitúa antes de la primera fila  hay que llamar a next para situarlo en la primera fila (¡si la hay!) </li></ul></ul><ul><ul><li>next() devuelve </li></ul></ul><ul><ul><ul><li>true , si el puntero ha avanzado a la siguiente fila </li></ul></ul></ul><ul><ul><ul><li>false , si no quedan más filas que procesar </li></ul></ul></ul>ResultSet rs = stmt.executeQuery(&quot;SELECT a, b, c FROM Table2&quot;); while (rs.next()) { ... Tratamiento de cada fila }
    32. 33. El interface ResultSet (II) <ul><li>Se obtienen los valores de la fila actual utilizando las distintas versiones del método get <tipo>(<columna>) pudiendo indicar la columna mediante su nombre o mediante su posición ( comienza por la 1 ). </li></ul><ul><li>Ejemplo: devolverá N filas, con la columna 1 como un int, la 2 como un String y la 3 como una fecha </li></ul><ul><li>Conviene cerrar el ResultSet aunque se cierra implícitamente al cerrar o reutilizar el Statement que lo creó. </li></ul>ResultSet rs = stmt.executeQuery(&quot;SELECT a, b, c FROM Table1&quot;); while (rs.next()) { int i = rs.getInt(&quot;a&quot;); // rs.getInt(1) String s = rs.getString(&quot;b&quot;); // rs.getString(2) java.sql.Date f = rs.getDate(&quot;c&quot;); // rs.getDate (3) System.out.println(“FILA = &quot; + i + &quot; &quot; + s + &quot; &quot; + f); }
    33. 34. ResultSet y valores nulos <ul><li>Cuando se ha leído un null de SQL usando uno de los métodos get<tipo> , éste devuelve algo de lo siguiente: </li></ul><ul><ul><li>Un valor null de Java para aquellos métodos get<tipo> que devuelven objetos Java ( getString , getBigDecimal , getBytes , getDate , getTime , getTimestamp , …). </li></ul></ul><ul><ul><li>Un valor cero para getByte , getShort , getInt , getLong , getFloat y getDouble . </li></ul></ul><ul><ul><li>Un valor false para getBoolean. </li></ul></ul><ul><li>Para determinar si un valor resultado dado es null , primero debe intentarse leer la columna y usar el método de ResultSet wasNull() para ver si lo que acabamos de leer era null </li></ul>int i = rs.getInt(&quot;a&quot;); // si el valor es null, i vale 0 if (rs.wasNull() { ... }
    34. 35. Navegación por el ResultSet <ul><li>En principio sólo se puede avanzar por las filas de datos ( next() ) </li></ul><ul><li>No se puede retroceder, ni volver a procesar un ResultSet . </li></ul><ul><li>A partir de JDBC2, se incluyen métodos para ir hacia detrás, al principio, al final, a una fila determinada … </li></ul><ul><li>… pero tienen implicaciones en el rendimiento de la aplicación </li></ul>
    35. 36. Tipos de datos y get<Tipo> <ul><li>Una “x” indica que el método get <tipo> puede legalmente usarse para recuperar el tipo JDBC dado. </li></ul><ul><li>Una “ X ” indica que el método get <tipo> es el recomendado para recuperar el tipo de dato dado. </li></ul>
    36. 37. Tipos de datos y get<Tipo> 
    37. 38. Ejemplo completo try { Class.forName(&quot;oracle.jdbc.driver.OracleDriver&quot;); } catch (ClassNotFoundException e) { System.err.println(&quot;No se ha podido cargar el driver de la BD&quot;); } Connection con = null ; try { String url = &quot;jdbc:oracle:thin:@localhost:1521:PBD&quot;; con = DriverManager.getConnection(url, &quot;PBD&quot;, &quot;pbdpbd&quot;); Statement stmt = con.createStatement(); ResultSet rs = stmt.executeQuery(&quot;SELECT a, b, c FROM Table1&quot;); while (rs.next()) { int i = rs.getInt(&quot;a&quot;); // rs.getInt(1) String s = rs.getString(&quot;b&quot;); // rs.getString(2) java.sql.Date f = rs.getDate(&quot;c&quot;); // rs.getDate (3) System.out.println(“FILA = &quot; + i + &quot; &quot; + s + &quot; &quot; + f); } try { Class.forName(&quot;oracle.jdbc.driver.OracleDriver&quot;); } catch (ClassNotFoundException e) { System.err.println(&quot;No se ha podido cargar el driver de la BD&quot;); } Connection con = null ; try { String url = &quot;jdbc:oracle:thin:@localhost:1521:PBD&quot;; con = DriverManager.getConnection(url, &quot;PBD&quot;, &quot;pbdpbd&quot;); Statement stmt = con.createStatement(); ResultSet rs = stmt.executeQuery(&quot;SELECT a, b, c FROM Table1&quot;); while (rs.next()) { int i = rs.getInt(&quot;a&quot;); // rs.getInt(1) String s = rs.getString(&quot;b&quot;); // rs.getString(2) java.sql.Date f = rs.getDate(&quot;c&quot;); // rs.getDate (3) System.out.println(“FILA = &quot; + i + &quot; &quot; + s + &quot; &quot; + f); } Carga del driver try { Class.forName(&quot;oracle.jdbc.driver.OracleDriver&quot;); } catch (ClassNotFoundException e) { System.err.println(&quot;No se ha podido cargar el driver de la BD&quot;); } Connection con = null ; try { String url = &quot;jdbc:oracle:thin:@localhost:1521:PBD&quot;; con = DriverManager.getConnection(url, &quot;PBD&quot;, &quot;pbdpbd&quot;); Statement stmt = con.createStatement(); ResultSet rs = stmt.executeQuery(&quot;SELECT a, b, c FROM Table1&quot;); while (rs.next()) { int i = rs.getInt(&quot;a&quot;); // rs.getInt(1) String s = rs.getString(&quot;b&quot;); // rs.getString(2) java.sql.Date f = rs.getDate(&quot;c&quot;); // rs.getDate (3) System.out.println(“FILA = &quot; + i + &quot; &quot; + s + &quot; &quot; + f); } Conexión try { Class.forName(&quot;oracle.jdbc.driver.OracleDriver&quot;); } catch (ClassNotFoundException e) { System.err.println(&quot;No se ha podido cargar el driver de la BD&quot;); } Connection con = null ; try { String url = &quot;jdbc:oracle:thin:@localhost:1521:PBD&quot;; con = DriverManager.getConnection(url, &quot;PBD&quot;, &quot;pbdpbd&quot;); Statement stmt = con.createStatement(); ResultSet rs = stmt.executeQuery(&quot;SELECT a, b, c FROM Table1&quot;); while (rs.next()) { int i = rs.getInt(&quot;a&quot;); // rs.getInt(1) String s = rs.getString(&quot;b&quot;); // rs.getString(2) java.sql.Date f = rs.getDate(&quot;c&quot;); // rs.getDate (3) System.out.println(“FILA = &quot; + i + &quot; &quot; + s + &quot; &quot; + f); } Consulta try { Class.forName(&quot;oracle.jdbc.driver.OracleDriver&quot;); } catch (ClassNotFoundException e) { System.err.println(&quot;No se ha podido cargar el driver de la BD&quot;); } Connection con = null ; try { String url = &quot;jdbc:oracle:thin:@localhost:1521:PBD&quot;; con = DriverManager.getConnection(url, &quot;PBD&quot;, &quot;pbdpbd&quot;); Statement stmt = con.createStatement(); ResultSet rs = stmt.executeQuery(&quot;SELECT a, b, c FROM Table1&quot;); while (rs.next()) { int i = rs.getInt(&quot;a&quot;); // rs.getInt(1) String s = rs.getString(&quot;b&quot;); // rs.getString(2) java.sql.Date f = rs.getDate(&quot;c&quot;); // rs.getDate (3) System.out.println(“FILA = &quot; + i + &quot; &quot; + s + &quot; &quot; + f); } Procesar resultado
    38. 39. Ejemplo completo (II) ... rs.close(); stmt.close(); } catch (SQLException e) { e.printStackTrace(); } finally { try { if (con != null ) con.close(); } catch (SQLException e) { e.printStackTrace(); } } ... rs.close(); stmt.close(); } catch (SQLException e) { e.printStackTrace(); } finally { try { if (con != null ) con.close(); } catch (SQLException e2) { e2.printStackTrace(); } } Cerrar TODO
    39. 40. Ejemplo de prácticas package sol; import bd.AbstractDBManager; import java.sql.*; import model.*; public class GestorBD extends AbstractDBManager { // Registro del driver apropiado para la BD a utilizar static { try { Class.forName(&quot;oracle.jdbc.driver.OracleDriver&quot;); } catch (ClassNotFoundException e) { System.out.println(&quot;No puedo cargar el driver JDBC de la BD&quot;); } } public Articulo getArticulo(String codigo) { } }
    40. 41. public Articulo getArticulo(String codigo) { Articulo articulo = null ; Connection con = null ; try { con = DriverManager.getConnection (&quot;jdbc:oracle:thin:@localhost:1521:pbd&quot;, &quot;prbd&quot;, &quot;prbdprbd&quot;); Statement stm = con.createStatement (); String sql = &quot; SELECT nombre, PVP FROM Articulo WHERE codigo =' &quot; +codigo+ &quot; ' &quot;; ResultSet res = stm.executeQuery(sql); if ( res.next() ) { articulo = new Articulo(codigo, res.getString(&quot;nombre&quot;) , res.getDouble(&quot;PVP&quot;) ); } res.close(); stm.close(); } catch (SQLException e) { e.printStackTrace(); } finally { if (con != null ) try { con.close(); } catch (SQLException ex) { ex.printStackTrace(); } } return articulo; }
    41. 42. El interface PreparedStatement <ul><li>Cada vez que se lanza un Statement el SGBD debe interpretarla y calcular un plan de consulta </li></ul><ul><li>La clase PreparedStatement permite lanzar comandos SQL precompilados. </li></ul><ul><li>En sentencias que van a ser ejecutadas múltiples veces se obtiene un aumento de rendimiento al tener la consulta ya analizada y optimizada. </li></ul><ul><li>Los objetos PreparedStatement se obtienen de la conexión, mediante el método prepareStatement(<sql>) </li></ul>Connection con = DriverManager.getConnection(url, usr, pwd); PreparedStatement stmt = con. prepareStatement(... SQL ...) ;
    42. 43. El interface PreparedStatement <ul><li>Otro uso de PreparedStatement es la posibilidad de parametrizar las consultas </li></ul><ul><li>La sentencia SQL puede contiene uno o más parámetros de entrada (indicados por ‘?’) los cuales podrán ser modificados en distintas ejecuciones de la sentencia. </li></ul><ul><li>Esta funcionalidad puede ser útil cuando no se sabe cómo escribir los valores de ciertos tipos de datos en el SQL del SGBD destino (ejemplo, los valores DATE, boolean). </li></ul><ul><li>También puede evitar “inyecciones de SQL” </li></ul>PreparedStatement ps = con.prepareStatement(&quot;UPDATE table SET sueldo= ? WHERE nombre= ? &quot;);
    43. 44. Inyección de SQL <ul><li>Detrás de un formulario de autenticación habrá una consulta como: </li></ul><ul><ul><li>SELECT * FROM users WHERE usr=‘Bob’ and pwd=‘2kjlu’ </li></ul></ul><ul><li>Si la consulta devuelve resultado, el usuario puede entrar; si no, adiós muy buenas. </li></ul><ul><li>El código de la aplicación concatena la consulta basándose en el contenido de los campos del formulario: </li></ul><ul><ul><li>&quot;SELECT * FROM users WHERE usr='&quot;+ elUsuario +&quot;' and pwd='&quot;+ laContraseña +&quot;'&quot; </li></ul></ul><ul><li>Ej: SELECT * FROM users WHERE usr=' fco ' and pwd=' xx ' </li></ul><ul><li>Si el usuario mete </li></ul><ul><ul><li>Como usuario: admin </li></ul></ul><ul><ul><li>Como contraseña: MeDaIgual' OR '1'='1 </li></ul></ul><ul><li>La cosa queda: </li></ul><ul><ul><li>SELECT * FROM users WHERE usr=' admin ' and pwd=' MeDaIgual' OR '1'='1 ' </li></ul></ul>
    44. 45. El interface PreparedStatement <ul><li>Antes de que la sentencia SQL pueda ser ejecutada deberemos asignar algún valor a los parámetros de entrada </li></ul><ul><li>La asignación se realiza mediante el método set<tipo>() siendo el tipo compatible con el del parámetro. </li></ul><ul><li>El método set<tipo> lleva dos argumentos: </li></ul><ul><ul><li>La posición del parámetro a asignar dentro de la sentencia (el primero es el 1). </li></ul></ul><ul><ul><li>El valor a asignar al parámetro. </li></ul></ul><ul><li>Finalmente se ejecuta la sentencia: </li></ul><ul><ul><ul><ul><li>ps.executeUpdate(); </li></ul></ul></ul></ul>PreparedStatement ps = con.prepareStatement(&quot;UPDATE table SET sueldo= ? WHERE nombre= ? &quot;); ps.setFloat(1, 1500.0); ps.setString(2, “Pepe&quot;); ps.executeUpdate();
    45. 46. Ejemplo try { Class.forName(&quot;oracle.jdbc.driver.OracleDriver&quot;); } catch (ClassNotFoundException e) { System.err.println(&quot;No se ha podido cargar el driver de la BD&quot;); } Connection con = null ; try { String url = &quot;jdbc:oracle:thin:@localhost:1521:PBD&quot;; con = DriverManager.getConnection(url, &quot;PBD&quot;, &quot;pbdpbd&quot;); float sueldos [] = {1500, 2000, 1205.75f}; String nombres [] = {&quot;Juan&quot;,&quot;Ana&quot;,&quot;Maria&quot;}; PreparedStatement ps = con.prepareStatement(&quot;UPDATE table SET sueldo=? WHERE nombre=?&quot;); for ( int i=0;i<sueldos.length;i++) { ps.setFloat(1,sueldos[i]); ps.setString(2,nombres[i]); ps.executeUpdate(); } ps.close();
    46. 47. Ejemplo (II) } catch (SQLException e) { e.printStackTrace(); } finally { try { if (con != null ) con.close(); } catch (SQLException e2) { e2.printStackTrace(); } }
    47. 48. Parámetros con valores null <ul><li>Cuando se pasa un valor null Java en alguno de los métodos set<tipo>() , se almacena un valor SQL null en la BD. </li></ul><ul><li>Si son valores de tipos primitivos ( int , float , boolean , …) </li></ul><ul><ul><li>El método a utilizar es setNull() </li></ul></ul><ul><ul><li>Hay que indicar el tipo </li></ul></ul>PreparedStatement ps = con.prepareStatement(“INSERT INTO Persona(nombre, casado) VALUES (?,?)&quot;); ps.setString (1, &quot;Juan&quot;); ps.setNull(2, java.sql.Types.BOOLEAN);
    48. 49. Notas sobre fechas (Oracle) <ul><li>Al almacenar fechas en Oracle podemos perder precisión </li></ul><ul><li>Oracle tiene dos (tres) tipos para fechas: </li></ul><ul><ul><li>DATE: que almacena fechas con hora,minutos y segundos </li></ul></ul><ul><ul><li>TIMESTAMP: que almacena fechas con hora,minutos, segundos y fracciones de segundo </li></ul></ul><ul><li>Cualquiera de los dos tipos de campos puede consultarse / almacenarse con setDate / getDate o setTimestamp / getTimestamp </li></ul><ul><li>Pero: </li></ul><ul><ul><li>setDate no almacena datos sobre la hora, sólo la fecha (la hora la pone a 00:00:00) </li></ul></ul><ul><ul><li>getDate no recupera datos sobre la hora (aunque sí esté en la BD) </li></ul></ul><ul><ul><li>setTimestamp / getTimestamp sí almacenan y recuperan datos sobre la hora. Si el campo es de tipo TIMESTAMP (en Oracle) incluso recuperan los datos sobre fracciones de segundo </li></ul></ul>
    49. 50. El interface CallableStatement <ul><li>Los objetos CallableStatement proporcionan un mecanismo para invocación de stored procedures de la base de datos. </li></ul><ul><li>Se obtienen de Connection mediante el método prepareCall(...) </li></ul><ul><li>La sintaxis de la invocación es: </li></ul><ul><ul><li>{[? = ]call <procedure_name>[(?, ?, ...)]} </li></ul></ul><ul><li>Los procedimientos almacenados pueden tener parámetros de tres tipos </li></ul><ul><ul><li>Los parámetros IN se tratan como en PreparedStatement . </li></ul></ul><ul><ul><li>Los parámetros OUT hay que registrarlos mediante: </li></ul></ul><ul><ul><ul><li>registerOutParameter(<indice>, <tipo>); </li></ul></ul></ul><ul><ul><li>Los parámetros INOUT se le da valor como a los IN y se registran como los OUT </li></ul></ul><ul><li>Finalmente se ejecuta la sentencia y se recogen los valores OUT con la familia de métodos get<tipo>(<indice>) </li></ul>
    50. 51. Ejemplo <ul><li>Supongamos una función llamada PrecioArticulo que devuelve el precio de una cantidad de artículos </li></ul>// Carga del driver ... Connection con = null ; try { String url = &quot;jdbc:oracle:thin:@localhost:1521:PBD&quot;; con = DriverManager.getConnection(url, &quot;PBD&quot;, &quot;pbdpbd&quot;); CallableStatement call=con.prepareCall(&quot;{?=call PrecioArticulo(?,?)}&quot;); call.registerOutParameter(1, Types.DOUBLE); call.setString(2, &quot;D786SCO&quot;); call.setInt(3, 10); call.executeQuery(); precioLinea = call.getDouble(1); call.close(); } ... cerrar la conexión
    51. 52. Ejemplo (II) <ul><li>Un procedimiento ( swap ) de intercambio de valores (dos parámetros INOUT) </li></ul>// Carga del driver ... Connection con = null ; try { // ... Establecimiento de la conexión CallableStatement call = con.prepareCall(“{call swap(?, ?)}&quot;); call.registerOutParameter(1, Types.INTEGER); call.registerOutParameter(2, Types.INTEGER); call.setInt(1, 1); call.setInt(2, 2); call.execute(); int r1 = call.getInt(1); int r2 = call.getInt(2); call.close(); System.out.println(&quot;Los valores ahora son &quot;+r1+&quot; y &quot;+r2); } ... cerrar la conexión
    52. 53. Agenda <ul><li>Introducción </li></ul><ul><li>Drivers JDBC </li></ul><ul><li>La clase DriverManager </li></ul><ul><li>Conexiones </li></ul><ul><li>Ejecución de instrucciones </li></ul><ul><li>Transacciones y SQL </li></ul><ul><li>Cuando las cosas van mal </li></ul><ul><li>Temas avanzados </li></ul><ul><li>JDBC 2 </li></ul>
    53. 54. Transacciones en JDBC <ul><li>Una transacción es un conjunto de sentencias que se deben completar o anular en su totalidad. </li></ul><ul><li>Cuando se inicia una transacción la forma de hacerla definitiva es mediante el método commit() del interface Connection . </li></ul><ul><li>Si se desean deshacer todas las sentencias de la transacción hay que invocar al método rollback() del interface Connection . </li></ul><ul><li>Las conexiones están por defecto en modo autoCommit, es decir, las sentencias se auto-confirman sin necesidad de llamar a commit() cuando finalizan (luego cada sentencia es una transacción). </li></ul>
    54. 55. Transacciones en JDBC <ul><li>El modo autoCommit se activa/desactiva con el método setAutoCommit(boolean on) del interface Connection . </li></ul><ul><li>Si el modo autoCommit está desactivado las transacciones no finalizarán hasta que se llame a commit() o rollback() explícitamente. </li></ul><ul><li>A su vez dichos métodos inician una nueva transacción, por lo que una transacción serán todas aquellas sentencias ejecutadas entre dos commit y/o rollback consecutivos. </li></ul><ul><li>También se puede establecer un punto de recuperación con el método setSavePoint() del interface Connection (desde JDBC 3.0). </li></ul>
    55. 56. Ejemplo ... Carga del driver ... String URL = &quot;jdbc:oracle:thin:@localhost:1521:PBD&quot;; Connection con = null ; try { con = DriverManager.getConnection(URL, &quot;PBD&quot;, &quot;pbdpbd&quot;); con.setAutoCommit( false ); float sueldos [] = {1500, 2000, 1205.75f}; String nombres [] = {&quot;Juan&quot;,&quot;Ana&quot;,&quot;Maria&quot;}; PreparedStatement ps =con.prepareStatement(&quot;UPDATE table SET sueldo=?&quot;+ &quot;WHERE nombre=?&quot;); for ( int i=0;i<sueldos.length;i++) { ps.setFloat(1,sueldos[i]); ps.setString(2,nombres[i]); ps.executeUpdate(); } ps.close(); con.commit();
    56. 57. Ejemplo (II) } catch (SQLException e) { e.printStackTrace(); try { if (con != null ) con.rollback(); } catch (SQLException e2) { e2.printStackTrace(); } } finally { try { if (con != null ) con.close(); } catch (SQLException e2) { e2.printStackTrace(); } }
    57. 58. Control de la concurrencia <ul><li>¿Que ocurre cuando un proceso está realizando una transacción (no se sabe si la confirmará o no) y otro intenta acceder a filas afectadas por la transacción? </li></ul><ul><li>El programador debe decidir como debe comportarse la conexión en ese caso mediante el método setTransactionIsolation(<tipo>) . </li></ul><ul><ul><li>TRANSACTION_READ_UNCOMMITTED (dirty reads): Se lee siempre la última versión de los datos aunque se encuentren sin confirmar (si luego se hace un rollback los datos son erróneos). </li></ul></ul><ul><ul><li>TRANSACTION_READ_COMMITTED : Solo se leen datos confirmados. No se consideran los datos modificados en otra transacción hasta que no los confirme (con commit ). </li></ul></ul>
    58. 59. Control de la concurrencia (II) <ul><ul><li>TRANSACTION_REPEATABLE_READ : Solo se leen datos cofirmados. Además mantiene un lock sobre la fila actual de manera que otros procesos no pueden modificarla (aunque sí leerla). Cuando se cambia la fila actual el lock cambia de registro. </li></ul></ul><ul><ul><li>TRANSACTION_SERIALIZABLE : Solo se leen datos confirmados. Además mantiene un lock sobre todas las filas seleccionadas durante la transacción. Otros procesos no podrán modificar ninguna de ellas (aunque sí leerlas). </li></ul></ul>
    59. 60. Agenda <ul><li>Introducción </li></ul><ul><li>Drivers JDBC </li></ul><ul><li>La clase DriverManager </li></ul><ul><li>Conexiones </li></ul><ul><li>Ejecución de instrucciones </li></ul><ul><li>Transacciones y SQL </li></ul><ul><li>Cuando las cosas van mal </li></ul><ul><li>Temas avanzados </li></ul><ul><li>JDBC 2 </li></ul>
    60. 61. SQLException <ul><li>La mayoría de los métodos de las clases e interfaces JDBC lanzan la excepción java.sql.SQLException cuando se produce algún error con relación a la BD: </li></ul><ul><ul><li>No se puede conectar </li></ul></ul><ul><ul><li>La sentencia está mal construida </li></ul></ul><ul><ul><li>… </li></ul></ul><ul><li>SQLException es una exception explícita y proporciona </li></ul><ul><ul><li>Un mensaje explicativo sobre la causa del error - getMessage() </li></ul></ul><ul><ul><li>Un código (entero) que identifica al error - getErrorCode() </li></ul></ul><ul><ul><li>Un enlace a la siguiente excepción anidada - getNextException() </li></ul></ul>
    61. 62. Agenda <ul><li>Introducción </li></ul><ul><li>Drivers JDBC </li></ul><ul><li>La clase DriverManager </li></ul><ul><li>Conexiones </li></ul><ul><li>Ejecución de instrucciones </li></ul><ul><li>Transacciones y SQL </li></ul><ul><li>Cuando las cosas van mal </li></ul><ul><li>Temas avanzados </li></ul><ul><li>JDBC 2 </li></ul>
    62. 63. DatabaseMetaData <ul><li>La conexión proporciona información sobre la BD a la que se conecta </li></ul><ul><li>Para ello dispone del método getMetaData() que devuelve un objeto DatabaseMetaData al que se puede preguntar por: </li></ul><ul><ul><li>Información sobre la versión de BD y de driver </li></ul></ul><ul><ul><li>Propiedades sobre lo que puede hacer la BD y el driver: procedimientos almacenados, outer joins, … </li></ul></ul><ul><ul><li>Límites de la BD: nº máximo de conexiones concurrentes, máximo de columnas en tabla, … </li></ul></ul><ul><ul><li>Funciones que incluye la BD y tipos que soporta </li></ul></ul><ul><ul><li>Esquema de la BD: tablas, campos de cada tabla, claves primarias, foráneas, índices, privilegios </li></ul></ul>
    63. 64. ResultSetMetaData <ul><li>ResultSet proporciona información, además de sobre el contenido, sobre la estructura de los datos obtenidos en un SELECT. </li></ul><ul><li>Para ello dispone del método getMetaData() que devuelve un objeto ResultSetMetaData al que se puede preguntar por: </li></ul><ul><ul><li>El número de columnas que incluye </li></ul></ul><ul><ul><li>Las características de cada columna: nombre, tipo, precisión, escala </li></ul></ul><ul><ul><li>Si la columna puede contener valores nulos </li></ul></ul>
    64. 65. Secuencias de escape <ul><li>Los Statement pueden contener SQL con sintaxis de escape SQL. </li></ul><ul><li>La sintaxis de escape señala al driver que el código que lleva debe ser tratado diferentemente. </li></ul><ul><li>El driver traducirá la sintaxis de escape en código que entiende la BD en particular. </li></ul><ul><li>Ejemplos: </li></ul><ul><ul><li>escape para caracteres LIKE </li></ul></ul><ul><ul><li>d , t y ts para literales de fecha y tiempo </li></ul></ul><ul><ul><ul><li>una fecha se especifica en SQL JDBC mediante la sintaxis: {d 'yyyy-mm-dd'} </li></ul></ul></ul>st.executeQuery(&quot;SELECT * FROM Articulo WHERE Id LIKE '%' {escape ''};
    65. 66. Sobre conexiones <ul><li>Las conexiones son un recurso limitado: hay que cerrarlas </li></ul><ul><li>Pero cuando? ¿Tras cada transacción? </li></ul><ul><li>Regla general: si no es necesario usar la misma conexión a lo largo de varias interacciones, debe cerrarse </li></ul><ul><li>Se pueden conservar </li></ul><ul><ul><li>Si hay pocos usuarios concurrentes </li></ul></ul><ul><ul><li>Si hay que mantener las propiedades transaccionales en varias interacciones </li></ul></ul><ul><ul><li>Pero hay que comprobar que la conexión está viva (y no siempre funciona el isClosed() y hay que hacer queries como SELECT 7 FROM DUAL) </li></ul></ul><ul><li>Hay que cerrarla </li></ul><ul><ul><li>Si puede haber muchos usuarios conectados concurrentemente, por ejemplo en aplicaciones web. </li></ul></ul><ul><ul><ul><li>En estos casos tras cada servicio hay que cerrar la conexión. </li></ul></ul></ul><ul><li>Se suelen usar Pool de conexiones </li></ul>
    66. 67. Pool de Conexiones Aplicación DriverManager new Connection( con.close() Pool de Conexiones getConnection( getConnection(
    67. 68. Cuando usar PreparedStatement <ul><li>No todos los SGBDs lo soportan </li></ul><ul><li>En principio mejoran el rendimiento, aunque este no es el único método de mejora: </li></ul><ul><ul><li>Los SGBDs suelen cachear las queries (Oracle lo hace): ofrecen mucho rendimiento si se repite la misma query </li></ul></ul><ul><ul><li>Pero si la query se diferencia en el valor de algún parámetro, … la caché no actúa </li></ul></ul><ul><ul><li>En este caso puede ser mejor usar PreparedStatement . </li></ul></ul><ul><li>Los PreparedStatement están asociados a la conexión que los creó: </li></ul><ul><ul><li>viven mientras no se cierre la conexión </li></ul></ul><ul><li>Es necesario combinar la reutilización de PreparedStatement con pooling de conexiones. </li></ul><ul><ul><li>Los servidores de aplicaciones suelen hacerlo. </li></ul></ul>
    68. 69. <ul><li>“ The use of a Statement in JDBC should be 100% localized to being used for DDL (ALTER, CREATE, GRANT, etc) as these are the only statement types that cannot accept BIND VARIABLES. PreparedStatements or CallableStatements should be used for EVERY OTHER type of statement (DML, Queries). As these are the statement types that accept bind variables. This is a fact, a rule, a law -- use prepared statements EVERYWHERE ” </li></ul><ul><li>Tom Kyte, Oracle's VP </li></ul>
    69. 70. Agenda <ul><li>Introducción </li></ul><ul><li>Drivers JDBC </li></ul><ul><li>La clase DriverManager </li></ul><ul><li>Conexiones </li></ul><ul><li>Ejecución de instrucciones </li></ul><ul><li>Transacciones y SQL </li></ul><ul><li>Cuando las cosas van mal </li></ul><ul><li>Temas avanzados </li></ul><ul><li>JDBC 2 </li></ul>
    70. 71. Actualizaciones por lotes <ul><li>Ejecutar un conjunto de actualizaciones de “una tacada”. </li></ul><ul><li>No se pueden ejecutar SELECTs. </li></ul><ul><li>Para ejecutar un lote primero crear un Statement e ir añadiéndole updates SQL (con addBatch() ) </li></ul><ul><li>Se debería tratar al lote como una transacción poniendo el autocommit en falso, para luego hacer un commit() . </li></ul>Statement stmt = con.createStatement(); stmt.addBatch( &quot;... un INSERT, algo que no sea SELECT ...&quot;); stmt.addBatch( &quot;... ... stmt.executeBatch();
    71. 72. ResultSet recorrible y actualizable <ul><li>Con el ResultSet tradicional sólo se puede avanzar por los datos </li></ul><ul><li>Con JDBC2 es posible ir hacia delante y hacia atrás en un ResultSet . </li></ul><ul><li>El ResultSet debe ser configurado para tal cosa poniendo unos settings apropiados. </li></ul><ul><li>Los settings indican si se permite navegar por el ResultSet y si se deja editar su contenido. </li></ul><ul><ul><li>ResultSet.CONCUR_READ_ONLY , no se puede editar el contenido </li></ul></ul><ul><ul><li>ResultSet.CONCUR_UPDATABLE , sí se puede editar </li></ul></ul><ul><ul><li>ResultSet.TYPE_FORWARD_ONLY , solo se puede ir hacia adelante </li></ul></ul><ul><ul><li>ResultSet.TYPE_SCROLL_INSENSITIVE , se puede navegar; una vez consultados los datos si estos son cambiados por terceros no veremos los cambios </li></ul></ul><ul><ul><li>ResultSet.TYPE_SCROLL_SENSITIVE </li></ul></ul><ul><li>Estos settings se indican cuando se crea el Statement , debiéndose dar un valor para definir las características de navegabilidad y de modificafilidad. </li></ul><ul><li>Ej: los resultSets de la siguiente statement serán navegables pero no se podrán modificar: </li></ul>con.createStatement( ResultSet.TYPE_SCROLL_INSENSITIVE , ResultSet.CONCUR_READ_ONLY );
    72. 73. ResultSet recorrible y actualizable (II) <ul><li>Los movimientos se realizan con los métodos next() , previous() , relative(n) , absolute(n) , last() , first() , beforeFirst() , afterLast() , pudiendo saber en que fila se está con el getRow() . </li></ul><ul><li>Los drivers de BD pueden no dar soporte a estas características. </li></ul><ul><li>Incluso en drivers que si las soportan, determinadas queries complejas pueden devolver resultados que por ejemplo no sean modificables. </li></ul><ul><li>Como norma es preciso comprobar las características del ResultSet devuelto para ver cual es el modo en el que trabaja (con los métodos getType() y getConcurency() ). </li></ul><ul><li>Estas características tienen su impacto en el rendimiento de la aplicación </li></ul>
    73. 74. Nuevos tipos de datos <ul><li>Se pueden recuperar/almacenar en una base de datos objetos de tipo </li></ul><ul><ul><li>BLOB (Binary Large Objects) </li></ul></ul><ul><ul><li>CLOB (Character Large Objects). </li></ul></ul><ul><li>Se recuperan con los métodos getBlob() y getClob() de ResultSet , que devuelven objetos de tipo java.sql.Blob y java.sql.Clob , los cuales incorporan métodos para navegar por los contenidos de los objetos. </li></ul><ul><li>También se pueden recuperar ARRAYs con el método getArray() , que devuelve un objeto de tipo java.sql.Array . </li></ul>
    74. 75. javax.sql <ul><li>Incluye las extensiones JDBC para J2EE </li></ul><ul><li>Destinado a su empleo en servidores de aplicaciones (Weblogic, WebSphere, Oracle9iAS, JRun, JBoss, …) </li></ul><ul><li>Proporciona: </li></ul><ul><ul><li>Otro mecanismo de obtención de conexiones: </li></ul></ul><ul><ul><ul><li>Basado en DataSource </li></ul></ul></ul><ul><ul><ul><ul><li>Que hay que desplegar previamente </li></ul></ul></ul></ul><ul><ul><ul><ul><li>Pueden ser pooled </li></ul></ul></ul></ul><ul><ul><li>Gestión de transacciones distribuidas </li></ul></ul><ul><ul><li>Rowsets, como el CachedRowset </li></ul></ul>
    75. 76. Novedades JDBC 4.0 <ul><li>Carga automática de drives JDBC </li></ul><ul><ul><li>Usando el mecanismo de Proveedores de Servicio de Java SE </li></ul></ul><ul><li>Tipo de dato ROWID </li></ul><ul><li>Mejora en el soporte para CLOB y BLOB </li></ul><ul><li>Soporte para SQL/XML </li></ul><ul><li>Posibilidad de “des-envolver” las clases que implementan JDBC para acceder a funcionalidad propietaria de un SGBD concreto </li></ul><ul><li>Mejoras en la gestión de Connection y Statement en pool </li></ul><ul><li>Nuevas funciones escalares </li></ul><ul><li>Nuevos métodos en varios interfaces </li></ul>
    76. 77. Cosas que se quedan en el tintero <ul><li>La configuración y obtención de conexiones vía DataSources JDBC </li></ul><ul><li>El empleo de pools de conexiones </li></ul><ul><li>Empleo de datos de tipos CLOB y BLOB </li></ul>
    77. 78. } finally { try { if (presentacion != null ) presentacion.close(); } catch (SQLException e) { e.printStackTrace(); } }
    1. A particular slide catching your eye?

      Clipping is a handy way to collect important slides you want to go back to later.

    ×