Introducción a XML JDBC Básico Amparo López Gaona México, D.F. Octubre del 2004 Introducción a XML JDBC Básico Introducción JDBCT M es una API contenida en Java 2SDK que permite el acceso a virtualmente cualquier BD desde el lenguaje de programación Java. (java.sql) ODBC (Open Database Conectivity) = Interfaz entre las BD y las aplicaciones que corren bajo Windows. JDBC es una API en Java para ejecutar instrucciones SQL. Consta de un conjunto de clases e interfaces escritas en Java. JDBC Es una API a nivel SQL, es decir permite usar proposiciones SQL como argumentos de los métodos. La pareja Java-JDBC: • Permite escribir una aplicación que corra en cualquier plataforma. • Facilita el mapeo de relacional a objeto. • Independencia de la BD. • Cómputo distribuido. c Amparo López Gaona, 2004 Transparencia No. 1 Introducción a XML JDBC Básico Estructura de JDBC JDBC tiene la siguiente arquitectura: Aplicacion A Aplicacion B JDBC Oracle c Amparo López Gaona, 2004 Sybase Postgres Transparencia No. 2 Introducción a XML JDBC Básico ¿Qué hace JDBC? De manera simplista JDBC permite hacer tres cosas: Establecer conexión con una fuente de datos. (BD) Connection con = DriveManager.getConnection("jdbc:miDriver:miBD "miUsuario", "miClave"); Enviar proposiciones de consulta y actualización a la fuente de datos. (SQL) Statement stmt = con.createStatement(); ResultSet rs = stmt.executeQuery("SELECT a, b, c FROM tabla1"); Procesar resultados. while (rs.next()) { int x = getInt("a"); String s = getString("b"); float f = getFloat("c"); } c Amparo López Gaona, 2004 Transparencia No. 3 Introducción a XML JDBC Básico 1. Conexión con la BD Controlador (driver) es el intermediario entre la BD y Java. Cargar un controlador. Class.forName("sun.jdbc.odbc.JdbcOdbcDriver"); Class.forName("org.postgresql.Driver"); Establecer la conexión del controlador con el SABD. String url = "jdbc:postgresql:cafes"; String login = "alg"; String password = "mi.psswrd"; Connection con = DriverManager.getConnection (url, login, password); La conexión devuelta puede usarse para crear las proposiciones JDBC que reciben instrucciones SQL para el SABD. Información de controladores en: http://servlet.java.sun.com/products/jdbc/drivers c Amparo López Gaona, 2004 Transparencia No. 4 Introducción a XML JDBC Básico Excepciones JDBC permite ver las excepciones disparadas por el SABD y por Java. Éstas son: ClassNotFoundException disparada por el método Class.forName. Connection refused. Check that the hostname a , and that the postmaster is running with the -i flag, which e orking. SQLException por los métodos de JDBC. Estas excepciones tienen tres partes: mensaje, estado, código de error. c Amparo López Gaona, 2004 Transparencia No. 5 Introducción a XML JDBC Básico try { //Código que puede generar una excepción } catch(SQLException ex) { System.err.println("-----------SQLException------------\n"); System.err.println("Mensaje: " + ex.getMessage()); System.err.println("Estado SQL: " + ex.getSQLState()); System.err.println("Código de Error: " + ex.getErrorCode()); } Por ejemplo, al tratar de crear una tabla existente se obtiene un mensaje: -----------SQLException---------Mensaje: ERROR: Relation ’cafe’ already exists Estado SQL: null Código de Error: 0 c Amparo López Gaona, 2004 Transparencia No. 6 Introducción a XML JDBC Básico Ejemplo de conexión import java.sql.Connection; import java.sql.DriverManager; import java.sql.SQLException; /** * Este programa establece una conexión con la base de datos indicada. * Para ejecutarse debe darse java SoloConexion DRIVER URL UID PASSWORD */ public class SoloConexion { static public void main(String args[]) { Connection conexion = null; if( args.length != 4 ) { System.out.println("Sintaxis: java SoloConexion DRIVER URL UID PASSWORD"); return; } try { Class.forName(args[0]); } catch( Exception e ) { c Amparo López Gaona, 2004 Transparencia No. 7 Introducción a XML JDBC Básico e.printStackTrace(); return; } try { conexion = DriverManager.getConnection(args[1], args[2], args[3]); System.out.println("Conexion exitosa :)"); ... // Aquı́ podrı́a ir cualquier procesamiento adicional } catch( SQLException e ) { e.printStackTrace(); } finally { if( conexion != null ) { try { conexion.close(); } catch( SQLException e ) { e.printStackTrace(); } } } } } c Amparo López Gaona, 2004 Transparencia No. 8 Introducción a XML JDBC Básico 2. Envı́o de proposiciones SQL El acceso básico a la BD: • Actualizaciones (INSERT, UPDATE, CREATE, ...). • Consultas (SELECT). Existen tres clases para trabajar con las proposiciones SQL: • Statement para trabajar con una proposición SQL sin parámetros. • PreparedStatement para usar proposiciones SQL que se ejecutan con frecuencia, por tanto son pre-compiladas y pueden tomar parámetros. • CallableStatement para trabajar con procedimientos almacenados. c Amparo López Gaona, 2004 Transparencia No. 9 Introducción a XML JDBC Básico La clase Statement Un objeto Statement es el que permite enviar instrucciones SQL a la base de datos. Se crea un objeto Statement Statement stm = con.createStatement(); Se proporciona el método apropiado para ejecutar con la proposición SQL que se desea enviar. • executeUpdate. • executeQuery • execute Se procesan los resultados son: • Modificaciones. Un entero indicando la cantidad de tuplas actualizadas. • Consultas. Se obtiene un objeto de la clase ResultSet. • En caso de usar execute devuelve true si la instrucción devuelve al menos una tupla de la BD y false en otro caso. c Amparo López Gaona, 2004 Transparencia No. 10 Introducción a XML JDBC Básico Creación de tablas Se tiene una BD con el siguiente esquema: Café(nombre, id_proveedor, precio, ventas, total) -----Proveedor(id, nombre, calle, ciudad, estado, cp) -stmt.executeUpdate("CREATE TABLE Cafe (nombre VARCHAR(32) PRIMARY KEY" + "id_proveedor INTEGER, precio FLOAT" + "ventas INTEGER, total INTEGER," + "FOREIGN KEY id_proveedor REFERENCES Proveedor(id))"); String creaTabla "CREATE TABLE Cafe (nombre VARCHAR(32) PRIMARY KEY" + "id_proveedor INTEGER, precio FLOAT" + "ventas INTEGER, total INTEGER," + "FOREIGN KEY id_proveedor REFERENCES Proveedor(id))"; stmt.executeUpdate(creaTabla); c Amparo López Gaona, 2004 Transparencia No. 11 Introducción a XML JDBC Básico Llenado de la tabla Statement stmt = con.createStatement(); stmt.executeUpdate("INSERT INTO cafe " + "VALUES (’Colombiano’, 101, 92.0, 0, 0)"); stmt.executeUpdate("INSERT INTO cafe " + "VALUES (’Chiapas_Organico’, 49, 28.00, 0, 0)"); stmt.executeUpdate("INSERT INTO cafe " + "VALUES (’Pluma Oaxaca’, 150, 30.00, 0, 0)"); stmt.executeUpdate("INSERT INTO cafe " + "VALUES (’Chiapas_Descafeinado’, 101, 33.00, 0, 0)"); stmt.executeUpdate("INSERT INTO cafe " + "VALUES (’Mezcla_Casa, 49, 27.00, 0, 0)"); c Amparo López Gaona, 2004 Transparencia No. 12 Introducción a XML JDBC Básico Programa para creación y llenado import java.sql.*; //Para usar el paquete que contiene la API JDBC public class CreaTCafes { public static void main(String args[]) { String url = "jdbc:postgresql:cafes"; Connection con; String createString, crea2; createString = "create table cafe " + "(nombre varchar(32) primary key, " + "id_proveedor int, " + "precio float, " + "ventas int, " + "total int)"; crea2 = "create table proveedor " + ... Statement stmt; try { Class.forName("org.postgresql.Driver"); } catch(java.lang.ClassNotFoundException e) { System.err.print("ClassNotFoundException: "); System.err.println(e.getMessage()); } c Amparo López Gaona, 2004 Transparencia No. 13 Introducción a XML JDBC Básico try { con = DriverManager.getConnection(url, "amparo", "mi.psswrd"); stmt = con.createcStatement(); stmt.executeUpdate(createString); stmt.executeUpdate(crea2); stmt.executeUpdate("insert into CAFE " + "VALUES (’Colombiano’, 101, 92.0, 0, 0)"); stmt.executeUpdate("INSERT INTO cafe " + "VALUES (’Chiapas_Organico’, 49, 28.00, 0, 0)"); stmt.executeUpdate("INSERT INTO cafe " + "VALUES (’Pluma Oaxaca’, 150, 30.00, 0, 0)"); stmt.executeUpdate("INSERT INTO cafe " + "VALUES (’Chiapas_Descafeinado’, 101, 33.00, 0, 0)"); stmt.executeUpdate("INSERT INTO cafe " + "VALUES (’Mezcla_Casa, 49, 27.00, 0, 0)"); } catch(SQLException ex) { System.err.println("-----------SQLException------------\n"); while (ex != null){ //Para atrapar todas las excepciones System.err.println("Mensaje: " + ex.getMessage()); ... } } }} c Amparo López Gaona, 2004 Transparencia No. 14 Introducción a XML JDBC Básico Actualización String actualizaDatos = "UPDATE Cafe " + "SET ventas = 75 " + "WHERE nombre LIKE ’Colombiano’"; stmt.executeUpdate(actualizaDatos); stmt.executeUpdate("DELETE FROM Proveedor WHERE id = 109"); c Amparo López Gaona, 2004 Transparencia No. 15 Introducción a XML JDBC Básico Consulta ResultSet rs = stmt.executeQuery("SELECT nombre, precio FROM Cafe"); El objeto rs contiene las tuplas resultado de la consulta. Para acceder a ellas se tiene el método next() que devuelve true si hay datos y false en otro caso. Para extraer cada atributo de la tupla actual (la recuperada con next) se debe usar un método getXXX de acuerdo al tipo del atributo. String s = ""; float n; while (rs.next()) { s = rs.getString("nombre"); n = rs.getFloat("precio"); System.out.println(s + " " + n); } c Amparo López Gaona, 2004 Transparencia No. 16 Introducción a XML JDBC Básico La salida serı́a: Colombiano 92.00 Chiapas_Organico 28.00 Pluma Oaxaca 30.00 Chiapas_Descafeinado 33.00 Mezcla_Casa 27.00 En lugar de recuperar los atributos por su nombre, también se puede hacer por su posición: 1, 2, etc... while (rs.next()) { String s = rs.getString(1); float n = rs.getFloat(2); System.out.println(s + " " + n); } c Amparo López Gaona, 2004 Transparencia No. 17 Introducción a XML JDBC Básico Métodos getXXXX Tipo SQL BIT TINYINT SMALLINT INTEGER BIGINT REAL FLOAT DOUBLE DECIMAL NUMERIC CHAR VARCHAR LONGVARCHAR DATE TIME TIMESTAMP BINARY VARBINARY LONGVARBINARY c Amparo López Gaona, 2004 Tipo Java boolean byte short int long float double double java.math.BigDecimal java.math.BigDecimal java.lang.String java.lang.String java.lang.String java.sql.Date java.sql.Time java.sql.Timestamp byte[] byte[] byte[] Transparencia No. 18 Introducción a XML JDBC Básico Valores nulos Si en la base de datos hay un valor null, el método getInt() devuelve un cero. En Java se tiene un null pero es para referencias. Después de un getXXX se puede preguntar wasNull() para investigar si el valor recuperado es el nulo de SQL. c Amparo López Gaona, 2004 Transparencia No. 19 Introducción a XML JDBC Básico Proposiciones Pre-compiladas Si se desea realizar varias veces la misma instrucción con diferentes valores es conveniente usar una proposición preparada. Un objeto PreparedStatement debe tener una proposición SQL en su creación. Está se envı́a al SABD inmediatamente y se compila. PreparedStatement ventasReales = con.PrepareStatement( "UPDATE cafe SET ventas = ? WHERE nombre LIKE ?"); Existen métodos setXXX de la clase PreparedStatement para asignar valor a los parámetros. Para que se ejecute la instrucción se debe llamar al método executeUpdate(). ventasReales.setInt(1, 75); ventasReales.setString(2, "Colombiano"); ventasReales.executeUpdate(); ventasReales.setString(2, "Oaxaca"); ventasReales.executeUpdate(); c Amparo López Gaona, 2004 Transparencia No. 20 Introducción a XML JDBC Básico Para limpiar los datos de un parámetro hay dos opciones: Asignar un nuevo valor. Usar clearParameters. Otro ejemplo: PreparedStatement ventasReales = con.PrepareStatement( "UPDATE cafe SET ventas = ? WHERE nombre LIKE ?"); int [] ventasSemanales = {175, 150, 60, 155, 90}; String [] tipoCafe = {"Colombiano", "Oaxaca", "Chiapas_Descafeinado", "Chiapas_Organico", "Mezcla_Casa"}; int cuantos = tipoCafe.length; for (int i = 0; i < cuantos; i++) { ventasReales.setInt(1,ventasSemanales[i]); ventasReales.setString(2,tipoCafe[i]); ventasReales.executeUpdate(); } c Amparo López Gaona, 2004 Transparencia No. 21 Introducción a XML JDBC Básico Transacciones y JDBC Una transacción es una unidad lógica de trabajo. Al crear una conexión se está en modo auto-commit que significa que cada instrucción SQL se trata como una transacción. Para permitir agrupar instrucciones en una transacción se debe desactivar el modo de auto-commit vı́a la instrucción: con.setAutoCommit(false); La transacción termina al llamar al método commit o rollback. Para que se graben los cambios efectuados por la transacción se debe llamar explı́citamente al método commit. c Amparo López Gaona, 2004 Transparencia No. 22 Introducción a XML JDBC Básico Ejemplo de transacciones import java.sql.*; public class Transaccion { public static void main(String args[]) { String url = "jdbc:postgresql:cafes"; Connection con = null; Statement stmt; PreparedStatement actualizaVentas; PreparedStatement actualizaTotal; String nuevaVenta = "update cafe " + "set ventas = ? where nombre like ?"; String nuevoTotal = "update cafe " + "set total = total + ? where nombre like ?"; String consulta = "select nombre, ventas, total from cafe"; try { Class.forName("org.postgresql.Driver"); } catch(java.lang.ClassNotFoundException e) { System.out.print("ClassNotFoundException: "); System.out.println(e.getMessage()); } c Amparo López Gaona, 2004 Transparencia No. 23 Introducción a XML JDBC Básico try { con = DriverManager.getConnection(url, "amparo", "mi.psswrd"); actualizaVentas = con.prepareStatement(nuevaVenta); actualizaTotal = con.prepareStatement(nuevoTotal); int [] ventasSemanales = {175, 150, 60, 155, 90}; String [] cafes = {"Colombiano", "Chiapas Organico", "Pluma Oaxaca", "Chiapas Descafeinado", "Mezcla Casa"}; int len = cafes.length; con.setAutoCommit(false); for (int i = 0; i < len; i++) { actualizaVentas.setInt(1, ventasSemanales[i]); actualizaVentas.setString(2, cafes[i]); actualizaVentas.executeUpdate(); actualizaTotal.setInt(1, ventasSemanales[i]); actualizaTotal.setString(2, cafes[i]); actualizaTotal.executeUpdate(); con.commit(); } con.setAutoCommit(true); actualizaVentas.close(); actualizaTotal.close(); c Amparo López Gaona, 2004 Transparencia No. 24 Introducción a XML JDBC Básico } catch(SQLException ex) { System.out.println("SQLException: " + ex.getMessage()); if (con != null) try { System.out.println("La transacción ha sido abortada "); con.rollback(); } catch(SQLException e) { System.out.print("SQLException: "); System.out.println(e.getMessage()); } } finally { if (con != null) try {con.close();} catch(SQLException e) { e.printStackTrace();} } } } c Amparo López Gaona, 2004 Transparencia No. 25 Introducción a XML JDBC Básico Procedimientos Almacenados Un procedimiento almacenado (store procedure) es un grupo de instrucciones SQL que forman una unidad lógica y realizan un tarea particular. Pueden ser compilados y ejecutados con diferentes parámetros y resultados. Ventajas: Debido a que son precompilados se ejecutan mucho más rápido que cada instrucción por separado. Los errores de sintaxis pueden corregirse al momento de compilación no de ejecución. Los programadores Java sólo requieren el nombre del procedimiento, sus entradas y salidas. c Amparo López Gaona, 2004 Transparencia No. 26 Introducción a XML JDBC Básico Ejemplo Creación: String creaProcedure = "CREATE PROCEDURE lista_proveedores " + "AS " + "SELECT proveedor.nombre, cafe.nombre " + "FROM proveedor, cafe " + "WHERE proveedor.id = cafe.id_proveedor " + "ORDER BY proveedor.nombre"; Statement stmt = con.createStatement(); stmt.executeUpdate(creaProcedure); Uso: Para llamar al procedimiento se debe crear un objeto de la clase CallableStatem el cual contiene una llamada a un procedimiento almacenado no contiene el procedimiento. CallableStatement cs = con.prepareCall("{call lista_proveedores}"); ResultSet rs = cs.executeQuery(); c Amparo López Gaona, 2004 Transparencia No. 27 Introducción a XML JDBC Básico Ejemplo de un procedimiento con parámetros CREATE PROCEDURE calcula_interes (id IN INTEGER, bal OUT FLOAT) IS BEGIN select balance into bal from cuenta where cuenta_id = id; bal := bal + bal * 0.03; update cuenta set balance = bal where cuenta_id = id; END; c Amparo López Gaona, 2004 Transparencia No. 28 Introducción a XML JDBC Básico try { CallableStatement cs = con.prepareCall("{call calcula_interes(?,?)}"); cs.registerOutParameter(2, java.sql.Types.FLOAT); for(int i=1; i < cuentas.length; i++) { cs.setInt(1, cuentas[i].getId()); cs.execute(); System.out.println("Nuevo balance: "+ cs.getFloat(2)); } con.commit(); stm.close(); con.close(); } Si fuera una función la sintaxis serı́a {? = call nombre(?,?)} c Amparo López Gaona, 2004 Transparencia No. 29 Introducción a XML JDBC Básico JDBC 2.0 Con JDBC 2.0 es posible hacer lo siguiente: Moverse en cualquier dirección en el resultado de la consulta. Actualizar las tablas de la BD sin utilizar SQL. Enviar, en lote, un conjunto de instrucciones SQL a la BD. Usar los tipos de datos de SQL3. c Amparo López Gaona, 2004 Transparencia No. 30 Introducción a XML JDBC Básico Movimiento en el resultado El método createStatement puede tener dos parámetros: El primero puede ser: • TYPE FORWARD ONLY. * • TYPE SCROLL INSENSITIVE. • TYPE SCROLL SENSITIVE. El segundo parámetro: • CONCUR READ ONLY. * • CONCUR UPDATABLE. Es importante el orden de estos parámetros. Statement stmt = con.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_READ_ONLY); ResultSet srs = stmt.executeQuery("SELECT nombre, precio FROM cafe"); c Amparo López Gaona, 2004 Transparencia No. 31 Introducción a XML JDBC Básico Métodos para moverse en el ResultSet next. Se mueve hacia adelante. previous. Se mueve hacia atrás. afterLast,beforeFirst, first, last. Se mueve a la posición indicada. absolute(int). Se mueve a la tupla especificada en el parámetro. Si éste es negativo empieza a contar del final hacia arriba. relative (int). A partir de la posición actual, se mueve tantos lugares como se indique en su parámetro. getRow. Devuelve el número de tupla en que se está posicionado. isFirst, isLast, isBeforeFirst, isAfterLast. Devuelven un valor Booleano. moveToInsertRow y moveToCurrentRow. ¿Cuántos renglones hay en el resultado? ¿Cómo listar al revés? c Amparo López Gaona, 2004 Transparencia No. 32 Introducción a XML JDBC Básico Actualizaciones en lote Con JDBC 2.0 los objetos de Statement, PreparedStatement y CallableStatement tienen la capacidad de mantener una lista de comandos que pueden ser transmitos como un lote. Instrucciones: clearBatch. Borra todo lo que haya en la lista. Al crearla está limpia. addBatch. Agrega instrucciones a la lista. executeBatch. Envia la lista de instrucciones a la BD. c Amparo López Gaona, 2004 Transparencia No. 33 Introducción a XML JDBC Básico Mini ejemplo: El dueño del café ha decidido incluir cuatro nuevos tipos de cafés a la tabla Cafe. con.setAutoCommit(false); Statement stmt = con.createStatement(); stmt.addBatch("INSERT INTO cafe " + "VALUES(’Amareto’, 49, 29, 0, 0)"); stmt.addBatch("INSERT INTO cafe " + "VALUES(’Kenya’, 49, 110, 0, 0)"); stmt.addBatch("INSERT INTO cafe " + "VALUES(’Coatepec, 49, 30, 0, 0)"); stmt.addBatch("INSERT INTO cafe " + "VALUES(’Coatepec D’, 49, 35, 0, 0)"); int [] updateCounts = stmt.executeBatch(); con.commit(); con.setAutoCommit(true); Sólo se pueden enviar en un lote instrucciones que regresan valor numérico. En caso contrario se disparan las siguientes excepciones: SQLException. BatchUpdateException. c Amparo López Gaona, 2004 Transparencia No. 34 Introducción a XML JDBC Básico Al igual que en el procesamiento en lı́nea, el ejemplo es ineficiente debido al uso de Statement. con.setAutoCommit(false); PreparedStatement stmt = con.prepareStatement( "INSERT INTO cafe VALUES(?, ?, ?, ?, ?)"); stmt.setString(1,"Coatepec"); stmt.setInt(2,49); stmt.setInt(3,30); stmt.setInt(4,0); stmt.setInt(5,0); stmt.addBatch(); stmt.setInt((1,"Coatepec Descafeinado"); stmt.setInt(2,49); stmt.setInt(3,35); stmt.setInt(4,0); stmt.setInt(5,0); stmt.addBatch(); // Etc... int [] updateCounts = stmt.executeBatch(); con.commit(); con.setAutoCommit(true); c Amparo López Gaona, 2004 Transparencia No. 35 Introducción a XML JDBC Básico Actualizaciones a la BD Dos posibilidades: La tradicional, usando SQL: stmt.executeUpdate("UPDATE cafe SET precio = 35.50" + "WHERE nombre = Descafeinado"); La nueva, modificando al ResultSet. 1. El ResultSet debe ser actualizable: Statement stmt = con.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_UPDATABLE); Para verificar que el conjunto de resultados es actualizable existe el método getConcurrency() que devuelve: • 1007 para indicar que es sólo de lectura. • 1008 para indicar que es actualizable. c Amparo López Gaona, 2004 Transparencia No. 36 Introducción a XML 2. JDBC Básico Luego modificar el ResultSet vı́a updateXXX. ResultSet nuevoRS = stmt.executeQuery("SELECT nombre, precio FROM cafe"); nuevoRS.last(); nuevoRS.updateFloat("precio", 35.50); nuevoRS.updateRow(); Las instrucciones updateXXX actualizan el valor de la columna indicada, de la tupla en donde se encuentra el cursor. Recordar que la posición de la tupla es en el ResultSet no la en la BD. 3. Actualizar la base de datos con updateRow. Si se desea restaurar el valor anterior a la actualización (en el conjunto de resultados) se debe usar el método cancelRowUpdates pero antes de llamar a updateRow. nuevoRS.last(); nuevoRS.updateFloat("precio", 35.50); ... nuevoRS.cancelRowUpdates(); El precio se mantiene tanto en el resultset como en la BD debido a que no se llamo a updateRow. c Amparo López Gaona, 2004 Transparencia No. 37 Introducción a XML JDBC Básico Supresiones del conjunto de resultados Para eliminar tuplas sin usar SQL: 1. Estar en la posición correcta. 2. Borrarlo con la instrucción deleteRow Ejemplo: Eliminar el cuarto renglón. nuevoRS.absolute(4); nuevoRS.deleteRow(); Lo que sucede en el ResultSet depende de la implementación. Puede ser que elimine el renglón, lo marque como borrado o lo deje en blanco. c Amparo López Gaona, 2004 Transparencia No. 38 Introducción a XML JDBC Básico Inserciones a la BD Para insertar una nueva tupla modificando al ResultSet se debe: 1. Mover el cursor vı́a el método moveToInsertRow. 2. Asignar valor a cada columna con el método updateXXX apropiado. 3. Llamar al método insertRow para insertar esta nueva tupla en el conjunto de resultados y en la base de datos simultáneamente. c Amparo López Gaona, 2004 Transparencia No. 39 Introducción a XML JDBC Básico Ejemplo Connection con = DriverManager.getConnection("jdbc:mySubprotocol:mySubName"); Statement stmt = con.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_UPDATABLE); ResultSet nuevoRS = stmt.executeQuery("SELECT * FROM cafe"); nuevoRS.moveToInsertRow(); nuevoRS.updateString("nombre", "Java"); nuevoRS.updateInt("id_proveedor", 150); nuevoRS.updateFloat("precio", 35.50); nuevoRS.updateInt("ventas", 0); nuevoRS.updateInt("total", 0); nuevoRS.insertRow(); % % % % % nuevoRS.updateString(1, "Java"); nuevoRS.updateInt(2, 150); nuevoRS.updateFloat(3, 35.50); nuevoRS.updateInt(4, 0); nuevoRS.updateInt(5, 0); Si se omite algún valor, pone el definido por omisión, o nulo, o si no está en ninguno de los casos anterior dispara una excepción del tipo SQLException. c Amparo López Gaona, 2004 Transparencia No. 40 Introducción a XML JDBC Básico Uso de datos de SQL3 Los tipos de datos incorporados a SQL3 y denominados tipos de datos SQL3 son: BLOB (Binary Large Object) para almacenar grandes cantidas de datos como bytes. Este tipo es mapeado a Blob. CLOB (Character Large Object), para almacenar grandes cantidades de datos como caracters. Clob. ARRAY permite usar un arreglo como valor de una columna. Array. Tipos estructurados mapeados a Struct. Referencia (REF) mapeada a Ref. Tipo SQL3 BLOB CLOB ARRAY Tipo estructurado REF (tipo estructurado) c Amparo López Gaona, 2004 Método getXXX getBlob getClob getArray getObject getRef Método setXXX setBlob setClob setArray setObject setRef Método updateXXX updateBlob * updateClob * updateArray * updateObject updateRef * Transparencia No. 41 Introducción a XML JDBC Básico Metadatos Su objetivo es proporcionar las herramientas para evitar que el programador tenga que conocer a fondo la organización de la BD. Información acerca de los datos que no son de interés para el usuario final pero que si requiere el programador para manejar los datos. Existen dos interfaces en java.sql para los metadatos: ResultSetMetaData. Proporciona información acerca del tipo y propiedades de cada columna de un objeto ResultSet. DatabaseMetaData. Proporciona información acerca de una base de datos o un SABD particular. c Amparo López Gaona, 2004 Transparencia No. 42 Introducción a XML JDBC Básico ResultSetMetaData Como su nombre indica proporciona información acerca de los tipos y propiedades de las columnas en un objeto ResultSet regresado por una consulta a la BD. Un ejemplar de ResultSetMetaData contiene la información y sus métodos proporcionan el acceso a ella. Creación. Statment stmt = con.createStament(); ResultSet rs = stmt.executeQuery("select * from Cafe"); ResultSetMetaData rsmd = rs.getMetaData(); Uso. int nColumnas = rsmd.getColumnCount(); while (rs.next()) for (int i = 1; i < nColumnas; i++) { String s = rs.getString(i); System.out.print(s); } System.out.println(""); c Amparo López Gaona, 2004 Transparencia No. 43 Introducción a XML JDBC Básico Todos los métodos de esta clase devuelven información acerca de una columna particular en rs, excepto el método getColumnCount que devuelve la cantidad total de columnas en el resultado. Para obtener el nombre de las columnas se usa el método getColumnLabel: int nColumnas = rsmd.getColumnCount(); for(int i = 1; i < nColumnas; i++) { if (i > 1) System.out.println(","); String nombre = rsmd.getColumnLabel(i); System.out.print(nombre); } System.out.println(""); c Amparo López Gaona, 2004 Transparencia No. 44 Introducción a XML JDBC Básico La interfaz completa es: int getColumnCount() int getColumnType(int) int getColumnDisplaySize(int) int getPrecision(int) int getScale(int) int isNullable (int) String getColumnTypeName(int) String getColumnName(int) String getColumnLabel(int) c Amparo López Gaona, 2004 boolean boolean boolean boolean isWritable (int) isReadOnly(int) isSigned (int) isCaseSensitive (int) String getTableName(int) String getSchemaName(int) String getCatalogName(int) Transparencia No. 45 Introducción a XML JDBC Básico Imprime Tipo de columnas import java.sql.*; class ImprimeCols { public static void imprimeTipo(ResultSetMetaData rsmd) throws SQLException { int cols = rsmd.getColumnCount(); int tipo; String nombre; for (int i = 1; i <= cols; i++) { tipo = rsmd.getColumnType(i); nombre = rsmd.getColumnTypeName(i); System.out.print("Columna " + i + " es del tipo JDBC " + tipo); System.out.println(" y corresponde a " + nombre + " en la BD."); } } public static void main(String args[]) { String url = "jdbc:postgresql:cafes", login = "amparo", pss = "mi.psswrd"; Connection con; String consulta = "select * from cafe"; Statement stmt; c Amparo López Gaona, 2004 Transparencia No. 46 Introducción a XML JDBC Básico try { Class.forName("org.postgresql.Driver"); } catch(java.lang.ClassNotFoundException e) { System.err.print("ClassNotFoundException: "); System.err.println(e.getMessage()); } try { con = DriverManager.getConnection(url, login, pss); stmt = con.createStatement(); ResultSet rs = stmt.executeQuery(consulta); ResultSetMetaData rsmd = rs.getMetaData(); imprimeTipo(rsmd); System.out.println(""); stmt.close(); con.close(); } catch(SQLException ex) { System.err.print("SQLException: "); System.err.println(ex.getMessage()); } } } c Amparo López Gaona, 2004 Transparencia No. 47 Introducción a XML JDBC Básico La salida de este programa es: Columna Columna Columna Columna Columna 1 2 3 4 5 es es es es es del del del del del tipo tipo tipo tipo tipo c Amparo López Gaona, 2004 JDBC JDBC JDBC JDBC JDBC 12 y corresponde a varchar en la BD. 4 y corresponde a int4 en la BD. 8 y corresponde a float8 en la BD. 4 y corresponde a int4 en la BD. 4 y corresponde a int4 en la BD. Transparencia No. 48 Introducción a XML JDBC Básico DatabaseMetaData Proporciona información acerca de la BD para un objeto Connection. Usos principales: Conocer información acerca de la BD que se está usando. Permitir crear aplicaciones independientes de la BD. Creación: DatabaseMetaData dbmd = con.getMetaData(); Uso: int n = dbmd.getMaxTableNameLength(); c Amparo López Gaona, 2004 Transparencia No. 49 Introducción a XML JDBC Básico Existen más de 150 métodos en esta interfaz, éstos se clasifican de acuerdo al valor que devuelven: Métodos que devuelven cadenas. Tales como el URL, nombre del usuario, del producto, versión, nombre del controlador. Las palabras reservadas del SABD, funciones numéricas, de cadenas, del sistema, fecha/hora. Métodos que devuelven enteros. Generalmente tienen la forma getMaxXXX. Máximo número de caracteres permitidos en una instrucción, para un identificador. Métodos que devuelven Booleanos. Generalmente tienen la forma supportsXXX, donde XXX es la capacidad que soportan. De estos hay más de 70. Métodos que devuelven listas de información en objetos ResultSet, en este caso se usan de manera normal, con getXXX. ResultSet rs = dbmd.getSchemas(); while (rs.next()){ String s = rs.getString(1); System.out.println("NOmbre d esquema = " + s); } c Amparo López Gaona, 2004 Transparencia No. 50 Introducción a XML JDBC Básico Ejemplo import java.sql.*; public class TypeInfo { public static void main(String args[]) { String url = "jdbc:postgresql:cafes"; Connection con; DatabaseMetaData dbmd; try { Class.forName("org.postgresql.Driver"); } catch(java.lang.ClassNotFoundException e) { System.err.print("ClassNotFoundException: "); System.err.println(e.getMessage()); } try { con = DriverManager.getConnection(url, "amparo", "myPassword"); dbmd = con.getMetaData(); ResultSet rs = dbmd.getTypeInfo(); while (rs.next()) { String typeName = rs.getString("TYPE_NAME"); short dataType = rs.getShort("DATA_TYPE"); c Amparo López Gaona, 2004 Transparencia No. 51 Introducción a XML JDBC Básico String createParams = rs.getString("CREATE_PARAMS"); int nullable = rs.getInt("NULLABLE"); boolean caseSensitive = rs.getBoolean("CASE_SENSITIVE"); System.out.println("DBMS type " + typeName + ":"); System.out.println(" java.sql.Types: " + dataType); System.out.print(" parameters used to create: "); System.out.println(createParams); System.out.println(" nullable?: " + nullable); System.out.print(" case sensitive?: "); System.out.println(caseSensitive); System.out.println(""); } con.close(); } catch(SQLException ex) { System.err.println("SQLException: " + ex.getMessage()); } } } c Amparo López Gaona, 2004 Transparencia No. 52 Introducción a XML JDBC Básico Parte de la salida de este ejemplo: DBMS type varchar: java.sql.Types: 12 parameters used to create: null nullable?: 0 case sensitive?: false DBMS type date: java.sql.Types: 91 parameters used to create: null nullable?: 0 case sensitive?: false DBMS type time: java.sql.Types: 92 parameters used to create: null nullable?: 0 case sensitive?: false información necesaria para conectarse a la BD. c Amparo López Gaona, 2004 Transparencia No. 53 Introducción a XML JDBC Básico Monitor de terminal genérico Esta aplicación permite introducir proposiciones SQL en la lı́nea de comandos y ver el resultado formateado. Las instrucciones permitidas son: commit. Envı́a un commit a la BD. go. Envı́a la instrucción que tenga el buffer para que sea procesada como instrucción SQL. vı́a el método executeStatement() quit. Cierra la BD y termina la aplicación. reset. Limpia el buffer sin enviar su información a la BD. rollback. Aborta cualquier transacción inconclusa. show version. Despliega información acerca de este programa. c Amparo López Gaona, 2004 Transparencia No. 54 Introducción a XML JDBC Básico EL método main static public void main(String args[]) { DriverPropertyInfo[] required; StringBuffer buffer = new StringBuffer(); Properties props = new Properties(); boolean connected = false; Driver driver; String url; int line = 1; // Mark current input line if( args.length < 1 ) { System.out.println("Syntax: <java -Djdbc.drivers=DRIVER_NAME " + "TerminalMonitor JDBC_URL>"); return; } url = args[0]; try { driver = DriverManager.getDriver(url); } catch( SQLException e ) { c Amparo López Gaona, 2004 Transparencia No. 55 Introducción a XML JDBC Básico e.printStackTrace(); System.err.println("Unable to find a driver for the specified " + "URL."); return; } try { required = driver.getPropertyInfo(url, props); } catch( SQLException e ) { e.printStackTrace(); System.err.println("Unable to get driver property information."); return; } input = new BufferedReader(new InputStreamReader(System.in)); try { if( required.length < 1 ) { props.put("user", prompt("user: ")); props.put("password", prompt("password: ")); } else { for(int i=0; i<required.length; i++) { if( !required[i].required ) continue; props.put(required[i].name, c Amparo López Gaona, 2004 Transparencia No. 56 Introducción a XML JDBC Básico prompt(required[i].name + ": ")); } } } catch( IOException e ) { e.printStackTrace(); System.err.println("Unable to read property info."); return; } try { connection = DriverManager.getConnection(url, props); } catch( SQLException e ) { e.printStackTrace(); System.err.println("Unable to connect to the database."); } connected = true; System.out.println("Connected to " + url); while( connected ) { String tmp, cmd; if( line == 1 ) System.out.print("TM > "); c Amparo López Gaona, 2004 Transparencia No. 57 Introducción a XML JDBC Básico else System.out.print(line + " -> "); System.out.flush(); try { tmp = input.readLine(); } catch( java.io.IOException e ) { e.printStackTrace(); return; } cmd = tmp.trim(); if( cmd.equals("commit") ) { try { connection.commit(); System.out.println("Commit successful."); } catch( SQLException e ) { System.out.println("Error in commit: " + e.getMessage()); } buffer = new StringBuffer(); line = 1; } else if( cmd.equals("go") ) { if( !buffer.equals("") ) { c Amparo López Gaona, 2004 Transparencia No. 58 Introducción a XML JDBC Básico try { executeStatement(buffer); } catch( SQLException e ) { System.out.println(e.getMessage()); } } buffer = new StringBuffer(); line = 1; continue; } else if( cmd.equals("quit") ) { connected = false; continue; } else if( cmd.equals("reset") ) { buffer = new StringBuffer(); line = 1; continue; } else if( cmd.equals("rollback") ) { try { c Amparo López Gaona, 2004 Transparencia No. 59 Introducción a XML JDBC Básico connection.rollback(); System.out.println("Rollback successful."); } catch( SQLException e ) { System.out.println("An error occurred during rollback: " + e.getMessage()) } buffer = new StringBuffer(); line = 1; } else if( cmd.startsWith("show") ) { DatabaseMetaData meta; try { meta = connection.getMetaData(); cmd = cmd.substring(5, cmd.length()).trim(); if( cmd.equals("version") ) showVersion(meta); else System.out.println("show version"); } catch( SQLException e ) { System.out.println("Failed to load meta data: " + e.getMessage()); } c Amparo López Gaona, 2004 Transparencia No. 60 Introducción a XML JDBC Básico buffer = new StringBuffer(); line = 1; } else { buffer.append(" " + tmp); line++; continue; } } try { connection.close(); } catch( SQLException e ) { System.out.println("Error closing connection: " + e.getMessage()); } System.out.println("Connection closed."); } c Amparo López Gaona, 2004 Transparencia No. 61 Introducción a XML JDBC Básico EL método executeStatement static public void executeStatement(StringBuffer buff) throws SQLException { String sql = buff.toString(); Statement statement = null; try { statement = connection.createStatement(); if( statement.execute(sql) ) // true means the SQL was a SELECT processResults(statement.getResultSet()); else { // no result sets, see how many rows were affected int num; switch(num = statement.getUpdateCount()) { case 0: System.out.println("No rows affected."); break; case 1: System.out.println(num + " row affected."); break; default: System.out.println(num + " rows affected."); c Amparo López Gaona, 2004 Transparencia No. 62 Introducción a XML JDBC Básico } } } catch( SQLException e ) { throw e; } finally { // close out the statement if( statement != null ) { try { statement.close(); } catch( SQLException e ) { } } } } c Amparo López Gaona, 2004 Transparencia No. 63 Introducción a XML JDBC Básico EL método processResults static public void processResults(ResultSet results) throws SQLException { try { ResultSetMetaData meta = results.getMetaData(); StringBuffer bar = new StringBuffer(); StringBuffer buffer = new StringBuffer(); int cols = meta.getColumnCount(); int row_count = 0; int i, width = 0; // Prepare headers for each of the columns // The display should look like: // -------------------------------------// | Column One | Column Two | // -------------------------------------// | Row 1 Value | Row 1 Value | // -------------------------------------for(i=1; i<=cols; i++) width += meta.getColumnDisplaySize(i); c Amparo López Gaona, 2004 Transparencia No. 64 Introducción a XML JDBC Básico width += 1 + cols; for(i=0; i<width; i++) bar.append(’-’); bar.append(’\n’); buffer.append(bar.toString() + "|"); for(i=1; i<=cols; i++) { StringBuffer filler = new StringBuffer(); String label = meta.getColumnLabel(i); int size = meta.getColumnDisplaySize(i); int x; if( label.length() > size ) label = label.substring(0, size); if( label.length() < size ) { int j; x = (size-label.length())/2; for(j=0; j<x; j++) filler.append(’ ’); label = filler + label + filler; if( label.length() > size ) c Amparo López Gaona, 2004 Transparencia No. 65 Introducción a XML JDBC Básico label = label.substring(0, size); else while( label.length() < size ) label += " "; } buffer.append(label + "|"); } buffer.append("\n" + bar.toString()); while( results.next() ) { row_count++; buffer.append(’|’); for(i=1; i<=cols; i++) { StringBuffer filler = new StringBuffer(); Object value = results.getObject(i); int size = meta.getColumnDisplaySize(i); String str; if( results.wasNull() ) str = "NULL"; else str = value.toString(); c Amparo López Gaona, 2004 Transparencia No. 66 Introducción a XML JDBC Básico if( str.length() > size ) str = str.substring(0, size); if( str.length() < size ) { int j, x; x = (size-str.length())/2; for(j=0; j<x; j++) filler.append(’ ’); str = filler + str + filler; if( str.length() > size ) str = str.substring(0, size); else while( str.length() < size ) str += " "; } buffer.append(str + "|"); } buffer.append("\n"); } if( row_count == 0 ) buffer = new StringBuffer("No rows selected.\n"); else if( row_count == 1 ) c Amparo López Gaona, 2004 Transparencia No. 67 Introducción a XML JDBC Básico buffer = new StringBuffer("1 row selected.\n" + buffer.toString() + bar.toString()); else buffer = new StringBuffer(row_count + " rows selected.\n" + buffer.toString() + bar.toString()); System.out.print(buffer.toString()); System.out.flush(); } catch( SQLException e ) { throw e; } finally { try { results.close(); } catch( SQLException e ) { } } } c Amparo López Gaona, 2004 Transparencia No. 68 Introducción a XML JDBC Básico EL método showVersion static public void showVersion(DatabaseMetaData meta) { try { System.out.println("TerminalMonitor v2.0"); System.out.println("DBMS: " + meta.getDatabaseProductName() + " " + meta.getDatabaseProductVersion()); System.out.println("JDBC Driver: " + meta.getDriverName() + " " + meta.getDriverVersion()); } catch( SQLException e ) { System.out.println("Failed to get version info: " + e.getMessage()); } } } c Amparo López Gaona, 2004 Transparencia No. 69