Você está na página 1de 64

Introduccin al acceso a datos. 1.- Introduccin. 2.- Acceso a datos. Mediante ficheros. Bases de datos.

Mapeo objeto relacional (ORM). Bases de datos XML. Componentes. 2.1.- Qu estrategia o mtodo de acceso a datos usar. Depender de las alternativas que haya y del sistema de
informacin en estudio.

3.- Ficheros. Para guardar poca informacin, es mejor usarlos que usar otro mtodo. 3.1.- Uso ficheros en la actualidad. Por esta razn se emplea XML en tecnologas de comunicacin como, por ejemplo, en WML
(lenguaje de formato inalmbrico) y WAP (protocolo de aplicaciones inalmbricas).

4.- Bases de datos. 4.1.- Introduccin. Las ventajas que aportan los sistemas de bases de datos respecto a los sistemas de archivos convencionales son:
Independencia de los datos respecto de los procedimientos. Disminucin de las redundancias y en consecuencia, Disminucin de la posibilidad de que se produzca inconsistencia de datos. Mayor integridad de los datos. Mayor disponibilidad de los datos. Mayor seguridad de los datos. Mayor privacidad de los datos. Mayor eficiencia en la recogida, codificacin y entrada en el sistema. Lo que se suele denominar interfaz con el pasado y futuro: una base de datos debe estar abierta a reconocer informacin organizada fsicamente por otro software. Comparticin de los datos.

4.2.- Bases de datos relacionales. 4.3.- Bases de datos orientadas a objetos. una caracterstica general es que el lenguaje de programacin y el esquema de la
base de datos utilizan las mismas definiciones de tipos.

4.4.- Comparativa entre bases de datos relacionales y orientadas a objetos. Podemos decir que las ventajas de
un SGBDOO frente a las relacionales son: Permiten mayor capacidad de modelado. Extensibilidad Disposicin de un lenguaje de consulta ms expresivo. Adaptacin a aplicaciones avanzadas de base de datos. Prestaciones. Reglas de acceso. Clave.

4.4.1.- Desventajas de las bases de datos orientadas a objetos frente a las relacionales. Como
desventajas o puntos dbiles de las BBDDOO respecto a las relacionales podemos mencionar: La reticencia del mercado Carencia de un modelo de datos universal. Carencia de experiencia. Dificultades en optimizacin. 4.5.- Bases de datos objeto-relacionales. Con las Bases de Datos Objeto-Relacional se ampla el modelo relacional destacando las siguientes aportaciones: Se aumentan la variedad en los tipos de datos,se pueden crear nuevos tipos de datos Hay extensiones en el control de la Semntica de datos Objeto-Relacionales:Se pueden crear procedimientos almacenados y funciones que tengan un cdigo en algn lenguaje de programacin Se pueden compartir varias libreras de clases ya existentes, esto es lo que conocemos como reusabilidad. 5.- Acceso a bases de datos mediante conectores. Un driver JDBC es un componente software que posibilita a una aplicacin Java interaccionar con una base de datos. Mediante JDBC el programador puede enviar sentencias SQL, y PL/SQL a una base de datos relacional. JDBC permite embeber SQL dentro de cdigo Java. 6.- Mapeo objeto relacional (ORM). El mapeo objeto-relacional (Object-Relational Mapping, o ORM) consisten en una tcnica de programacin para convertir datos entre el sistema de tipos utilizado en un lenguaje de programacin orientado a objetos y el sistema utilizado en una base de datos relacional. Cuando se requiere almacenar la informacin de los objetos utilizando una base de datos relacional se comprueba que hay un problema de compatibilidad entre estos dos paradigmas, el llamado desfase objeto-relacional. 6.1.- Capa de persistencia y framework de mapeo. La capa de persistencia de una aplicacin es la pieza que permite almacenar, recuperar, actualizar y eliminar el estado de los objetos que necesitan persistir en un sistema gestor de datos. La capa de persistencia traduce entre los dos modelos de datos: desde objetos a registros y desde registros a objetos. As, si el programa quiere grabar un objeto, entonces llama al motor de persistencia, el motor de persistencia traduce el objeto a registros y llama a la base de datos para que guarde estos registros. Las comunidades open source incluyen importantes tecnologas, entre ellas Hibernate y el framework Spring. Las alternativas ms importantes basadas en el estndar, son EJB 3.0 y JDO. Entre las implementaciones comerciales se puede resaltar TopLink. 7.- Bases de datos XML. Las bases de datos XML nativas permiten trabajar con XQL (eXtensible Query Language), el cul sirve un propsito similar a SQL en una base de datos relacional. El trabajo con bases de datos XML nativas involucra dos pasos bsicos: Describir los datos mediante Definiciones de Tipos de Datos (Document Type Definitions, DTD) o esquemas XML y Definir un nuevo esquema de base de datos XML nativa o Mapa de Datos a usar para almacenar y obtener datos.

8.- Desarrollo de componentes. 8.1.- Definicin de componente. Un componente es una unidad de software que realiza una funcin bien definida y posee una
interfaz bien definida.

8.2.- JavaBeans. El origen de los JavaBeans lo podemos encontrar en un par de necesidades que Java tena:
Disponer de una tecnologa de objetos y componentes reutilizables. Mejorar el proceso para crear interfaces de usuario Un JavaBean es un componente software reutilizable basado en la especificacin JavaBean de Sun (ahora Oracle) que se puede manipular visualmente con una herramienta de desarrollo.

Manejo de ficheros. 1.- Introduccin. La librera java.io contiene las clases necesarias para gestionar las operaciones de entrada y salida con Java. 2.- Clases asociadas a las operaciones de gestin de ficheros y directorios. 2.1.- Clase File. La clase File proporciona una representacin abstracta de ficheros y directorios.
Dado un objeto File, podemos hacer las siguientes operaciones con l: Renombrar el archivo, con el mtodo renameTo(). El objeto File dejar de referirse al archivo renombrado, ya que el String con el nombre del archivo en el objeto File no cambia. Borrar el archivo, con el mtodo delete(). Tambin, con deleteOnExit() se borra cuando finaliza la ejecucin de la mquina virtual Java. Crear un nuevo fichero con un nombre nico. El mtodo esttico createTempFile() crea un fichero temporal y devuelve un objeto File que apunta a l. Es til para crear archivos temporales, que luego se borran, asegurndonos tener un nombre de archivo no repetido. Establecer la fecha y la hora de modificacin del archivo con setLastModified(). Por ejemplo, se podra hacer: new File("prueba.txt").setLastModified(new Date().getTime()); para establecerle la fecha actual al fichero que se le pasa como parmetro, en este caso prueba.txt. Crear un directorio, mediante el mtodo mkdir(). Tambin existe mkdirs(), que crea los directorios superiores si no existen. Listar el contenido de un directorio. Los mtodos list() y listFiles() listan el contenido de un directorio. list() devuelve un vector de String con los nombres de los archivos, listFiles() devuelve un vector de objetos File. Listar los nombres de archivo de la raz del sistema de archivos, mediante el mtodo esttico listRoots(). Para crear un objeto File nuevo, se puede utilizar cualquiera de los tres constructores siguientes: File miFichero; miFichero = new File( "/etc/kk" ); File f = new File("C:\texto.txt"); o miFichero = new File( "/etc","kk" ); o File miDirectorio = new File( "/etc" ); o miFichero = new File( miDirectorio,"kk" ); Nombres de fichero: String getName(); String getPath(); String getAbsolutePath(); String getParent(); boolean renameTo( File nuevoNombre ) Comprobaciones: boolean exists(); boolean canWrite(); boolean canRead(); boolean isFile(); boolean isDirectory(); boolean isAbsolute() Informacin general del fichero: long lastModified(); long length() Utilidades de directorio: boolean mkdir(); String[] list() import java.io.*; class InfoFichero { public static void main( String args[] ) throws IOException { if( args.length > 0 ) { for( int i=0; i < args.length; i++ ) { File f = new File( args[i] ); System.out.println( "Nombre: "+f.getName() ); System.out.println( "Camino: "+f.getPath() ); if( f.exists() ) { System.out.print( "Fichero existente " ); System.out.print( (f.canRead() ? " y se puede Leer" : "" ) ); System.out.print( (f.canWrite() ? " y se puese Escribir" : "" ) ); System.out.println( "." ); System.out.println( "La longitud del fichero son "+ f.length()+" bytes" ); } else System.out.println( "El fichero no existe." ); } } else System.out.println( "Debe indicar un fichero." ); } } 2.2.- Interface FilenameFilter. El interface FilenameFilter se puede usar para crear filtros que establezcan criterios de filtrado relativos al nombre de los ficheros. Una clase que lo implemente debe definir e implementar el mtodo: boolean accept(File dir, String nombre) Este mtodo devolver verdadero en el caso de que el fichero cuyo nombre se indica en el parmetro nombre aparezca en la lista de los ficheros del directorio indicado por el parmetro dir. import java.io.File; listadeArchivos = fichero.list(new Filtrar(".txt")); import java.io.FilenameFilter; // Comprobamos el nmero de archivos en el listado int numarchivos = listadeArchivos.length ; public class Filtrar implements FilenameFilter { // Si no hay ninguno lo avisamos por consola String extension; if (numarchivos < 1) // Constructor System.out.println("No hay archivos que listar"); Filtrar(String extension){ // Y si hay, escribimos su nombre por consola. this.extension = extension; else } { public boolean accept(File dir, String name){ for(int conta = 0; conta < listadeArchivos.length; return name.endsWith(extension); conta++) } System.out.println(listadeArchivos[conta]); public static void main(String[] args) { } try { } // Obtendremos el listado de los archivos de ese catch (Exception ex) { directorio System.out.println("Error al buscar en la ruta indicada"); File fichero=new File("c:\\datos\\."); } String[] listadeArchivos = fichero.list(); } // Filtraremos por los de extension .txt }

2.3.- Rutas de los ficheros. Para evitar problemas en la ejecucin de los programas cuando se ejecuten en uno u otro sistema
operativo y, por tanto, persiguiendo que nuestras aplicaciones sean lo ms portables posibles, se recomienda usar en Java: File.separator. String substFileSeparator(String ruta){ String separador = "\\"; try{ // Si estamos en Windows if ( File.separator.equals(separador) ) separador = "/" ; // Reemplaza todas las cadenas que coinciden con la expresin // regular dada oldSep por la cadena File.separator return ruta.replaceAll(separador, File.separator); }catch(Exception e){ // Por si ocurre una java.util.regex.PatternSyntaxException return ruta.replaceAll(separador + separador, File.separator); } }

2.4.- Creacin y eliminacin de ficheros y directorios.


Cuando queramos crear un fichero, podemos proceder del siguiente modo: try { // Creamos el objeto que encapsula el fichero File fichero = new File("c:\\prufba\\miFichero.txt"); // A partir del objeto File creamos el fichero fsicamente if (fichero.createNewFile()) System.out.println("El fichero se ha creado correctamente"); else System.out.println("No ha podido ser creado el fichero"); } catch (Exception ioe) { ioe.getMessage(); } Para borrar un fichero podemos usar la clase File, comprobando previamente si existe el fichero, del siguiente modo: fichero.delete(); Para crear directorios, podramos hacer: try { // Declaracin de variables String directorio = "C:\\prueba"; String varios = "carpeta1/carpeta2/carpeta3"; // Crear un directorio boolean exito = (new File(directorio)).mkdir(); if (exito) System.out.println("Directorio: " + directorio + " creado"); // Crear varios directorios exito = (new File(varios)).mkdirs(); if (exito) System.out.println("Directorios: " + varios + " creados"); }catch (Exception e){ System.err.println("Error: " + e.getMessage()); } Para borrar un directorio con Java, tendremos que borrar cada uno de los ficheros y directorios que ste contenga. Al poder almacenar otros directorios, se podra recorrer recursivamente el directorio para ir borrando todos los ficheros. Se puede listar el contenido del directorio e ir borrando con: File[] ficheros = directorio.listFiles(); Si el elemento es un directorio, lo sabemos mediante el mtodo isDirectory(). 3.- Flujos. Un programa en Java, que necesita realizar una operacin de entrada/salida (en adelante E/S), lo hace a travs de un flujo o stream. Un flujo es una abstraccin de todo aquello que produce o consume informacin. Java define dos tipos de flujos en el paquete java.io: Byte streams (8 bits): proporciona lo necesario para la gestin de entradas y salidas de bytes y su uso est orientado a la lectura y escritura de datos binarios. dos clases abstractas que son InputStream y OutputStream, mtodos implementados y, de entre todos, destacan read()y write(). Character streams (16 bits): de manera similar a los flujos de bytes, dos clases abstractas, en este caso: Reader y Writer. los mtodos read() y write().

3.1.- Flujos basados en bytes.


Las clases principales que heredan de OutputStream, para la escritura de ficheros binarios son: FileOutputStream: escribe bytes en un fichero. Si el archivo existe, cuando vayamos a escribir sobre l, se borrar. Por tanto, si queremos aadir los datos al final de ste, habr que usar el constructor FileOutputStream(String filePath, boolean append), poniendo append a true. ObjectOutputStream: convierte objetos y variables en vectores de bytes que pueden ser escritos en un OutputStream. DataOutputStream, que da formato a los tipos primitivos y objetos String, convirtindolos en un flujo de forma que cualquier DataInputStream, de cualquier mquina, los pueda leer. Todos los mtodos empiezan por "write", como writeByte(), writefloat(), etc. De InputStream, para lectura de ficheros binarios, destacamos: FileInputStream: lee bytes de un fichero. ObjectInputStream: convierte en objetos y variables los vectores de bytes ledos de un InputStream.

private void jButton1ActionPerformed(java.awt.event.ActionEvent evt) { // Nombre del feichero donde se escribir la informacin String fileName = "C:\\datosbinarios.dat" ; try { // Se declara un objeto de tipo DataOutputStream DataOutputStream fileOut = new DataOutputStream (new FileOutputStream(fileName)); // Escribir cadena de texto fileOut.writeUTF(jTextArea1.getText()); // Escribir un entero 5 fileOut.writeInt(5); } catch (IOException ioe) { System.out.print(ioe.getMessage()); } }

3.2.- Flujos basados en caracteres. Los BufferedReader, BufferedInputStream, BufferedWriter y BufferedOutputStream


aaden un buffer intermedio.En el ejemplo anterior para leer caracteres: private void jButton1ActionPerformed(java.awt.event.ActionEvent jTextArea1.append(linea + "\n"); evt) { } // TODO add your handling code here: } File archivo = null; catch(Exception e){ }finally{ FileReader fr = null; // En el finally cerramos el fichero, para asegurarnos BufferedReader br = null; // que se cierra tanto si todo va bien como si salta try { // Apertura del fichero y creacion de BufferedReader para // una excepcion. poder try{ // hacer una lectura comoda (disponer del metodo readLine()). if( null != fr ){ archivo = new File ("C:\\archivo.txt"); fr.close(); fr = new FileReader (archivo); } br = new BufferedReader(fr); }catch (Exception e2){ // Lectura del fichero } String linea; } while((linea=br.readLine())!=null){ } System.out.println(linea); 4.- Formas de acceso a un fichero. Acceso aleatorio. Acceso secuencial. Concatenacin (tuberas o "pipes").

4.1.- Operaciones bsicas sobre ficheros de acceso secuencial.


Grabar datos en fichero secuencial.

private void jButton1ActionPerformed(java.awt.event.ActionEvent evt) { // Declarar un objeto de tipo archivo DataOutputStream archivo = null; // Abir, capturar y grabar datos try { int edad = 0 ; // Creando o abriendo para aadir el archivo archivo = new DataOutputStream( new FileOutputStream("c:\\secuencial.dat",true) ); // Escribir el nombre y los apellidos archivo.writeUTF( jTextField1.getText() ); archivo.writeUTF( jTextField2.getText() ); // Obtener la edad edad = Integer.parseInt(jTextField3.getText());

// Escribir la edad archivo.writeInt(edad) ; // Cerrar fichero archivo.close(); } catch(FileNotFoundException fnfe) { /* Archivo no encontrado */ } catch (IOException ioe) { /* Error al escribir */ } catch (Exception e) { /* Error de otro tipo*/ System.out.println(e.getMessage());} }

Copiar fichero. La clase espera dos argumentos desde la lnea de comandos: nombre del fichero fuente y nombre del fichero donde se har la copia. Se utilizan las clases FileInputStream y FileOutputStream para leer desde el fichero origen, y copiar al fichero destino, respectivamente. import java.io.FileInputStream; // Leer del fuente hasta llegar la fin de archivo import java.io.FileOutputStream; int i = fuente.read(); import java.io.IOException; while (i != -1) { // mientras not EOF destino.write(i); public class copiar { i = fuente.read(); } public static void main(String args[]) { // Clase para leer los datos de un fichero // Cerrar los ficheros FileInputStream fuente = null; fuente.close(); // Clase para escribir los datos a un fichero destino.close(); FileOutputStream destino = null; }catch (IOException e) { try { System.out.println("Error en operaciones de ficheros"); // El fichero fuente es el primer parmetro } fuente = new FileInputStream(args[0]); } // El fichero destino es el segundo parmetro. } destino = new FileOutputStream(args[1],true); Streams de salida con buffer // Ahora se pueden utilizar los dos streams de entrada para Creacin de Streams de salida con buffer. // acceder al fichero (si se quiere) FileOutputStream miFileStream; miBufferStream.write( b ); BufferdOutpurStream miBufferStream; // Obtiene un controlador de fichero miDataStream.writeInt( i ); miFileStream = new FileOutputStream( "/tmp/kk" ); // Cierra el fichero de datos explcitamente. Siempre se cierra // Encadena un stream de salida con buffer // primero el fichero stream de mayor nivel miBufferStream = new BufferedOutputStream( miFileStream ); miDataStream.close(); miBufferStream.close(); Volcado y Cierre de Streams de salida con buffer miFileStream.close(); // Se fuerza el volcado del buffer a disco miBufferStream.flush(); Escritura en un objeto DataOutputStream // Cerramos el fichero de datos. Siempre se ha de cerrar primero el void writeBoolean( boolean b ); // fichero stream de mayor nivel void writeByte( int i ); miBufferStream.close(); void writeShort( int i ); miFileStream.close(); void writeChar( int i ); Streams DataOutput void writeInt( int i ); Apertura y cierre de objetos DataOutputStream void writeFloat( float f ); DataOutputStream miDataStream; void writeDouble( double d ); FileOutputStream miFileStream; void writeBytes( String s ); BufferedOutputStream miBufferStream; void writeChars( string s ); // Obtiene un controlador de fichero Contabilidad de la salida miFileStream = new FileOutputStream( "/tmp/kk" ); ... int numBytes = miDataStream.size() % 4; // Encadena un stream de salida con buffer (por eficiencia) miBufferStream = new BufferedOutputStream( miFileStream ); for( int i=0; i < numBytes; i++ ) // Encadena un fichero de salida de datos miDataStream.write( 0 ); ... miDataStream = new DataOutputStream( miBufferStream ); Las subclases de Writer y Reader que permiten trabajar con ficheros de texto son: FileReader, para lectura desde un fichero de texto. Crea un flujo de entrada que trabaja con caracteres en vez de con bytes. FileWriter, para escritura hacia un fichero de texto. Crea un flujo de salida que trabaja con caracteres en vez de con bytes. Tambin se puede montar un buffer sobre cualquiera de los flujos que definen estas clases: BufferedWriter se usa para montar un buffer sobre un flujo de salida de tipo FileWriter. BufferedReader se usa para montar un buffer sobre un flujo de entrada de tipo FileReader. Veamos un ejemplo de lectura utilizando un BufferReader. public class LeeconBuffer { public static void main(String[] args) { String texto = "" ; try { // Crear el flujo de salida FileReader fichero = null; // Ruta y nombre del fichero fichero = new FileReader("c:\\texto.txt"); // Montar un buffer sobre ese flujo BufferedReader buffer = new BufferedReader(fichero); // Escribimos el texto usando el metodo readLine() while ((texto = buffer.readLine()) != null) { System.out.println(texto); } // Cerrar fichero fichero.close(); } catch (IOException e) { // Escribir el error en la consola System.err.println("Error: " + e); } } } Ahora vamos a ver cmo buscar en un archivo secuencial, usando ese mismo ejemplo. Al pinchar en buscar:Acrion Perfonmance private void jButton1ActionPerformed(java.awt.event.ActionEvent evt) { String busqueda = jTextField1.getText() ; boolean seguir = true ; try{ String nombre = "" ; // Declarar variable String apellidos = "" ; DataInputStream archivo = null; int edad = 0 ; // Abrir el archivo

archivo = new DataInputStream( new FileInputStream("c:\\secuencial.dat") ); // Leer archivo while (seguir) { // Leer el nombre nombre = archivo.readUTF(); // Si el nombre es el que buscamos if (busqueda.equals(nombre)) { System.out.println("encontrado"); seguir = false ; jLabel2.setText("Encontrado registro!!"); }

// Leer los otros campos apellidos = archivo.readUTF(); edad=archivo.readInt(); } // Cerrar fichero archivo.close(); } catch(FileNotFoundException fnfe) { /* Archivo no encontrado */ } catch (IOException ioe) { /* Error al escribir */ } }

4.2.- Operaciones bsicas sobre ficheros de acceso aleatorio. Java proporciona una clase RandomAccessFile para
este tipo de entrada/salida. La clase posee dos constructores: RandomAccessFile(File file, String mode). RandomAccessFile(String name, String mode). El modo es: "r" si se abre en modo lectura o "rw" si se abre en modo lectura y escritura. Posee mtodos especficos de desplazamiento como seek(long posicion) o skipBytes(int desplazamiento) para poder movernos de un registro a otro del fichero, o posicionarnos directamente en una posicin concreta del fichero. Escribir en ficheros de acceso aleatorio. public static void main(String[] args)throws IOException { RandomAccessFile miRAFile; String s = "Cadena a escribir2\n"; // Abrimos el fichero de acceso aleatorio miRAFile = new RandomAccessFile( "C:\\aleatorio.bin","rw" ); // Nos vamos al final del fichero miRAFile.seek( miRAFile.length() ); // Incorporamos la cadena al fichero miRAFile.writeBytes( s ); // Cerramos el fichero miRAFile.close(); }

5.- Trabajo con ficheros XML: analizadores sintcticos (parser) y vinculacin (binding). 5.1.- Conceptos previos. 5.2.- Definiciones. Qu es y para qu sirve JAXB (Java Architecture for XML Binding)? JAXB simplifica el acceso a documentos XML
representando la informacin obtenida de los documentos XML en un programa en formato Java. Parsear un documento XML consiste en "escanear" el documento y dividirlo o separarlo lgicamente en piezas discretas. Binding: Binding o vincular un esquema (schema) significa generar un conjunto de clases Java que representan el esquema. Compilador de esquema o schema compiler: liga un esquema fuente a un conjunto de elementos de programa derivados. Binding runtime framework: proporciona operaciones de unmarshalling y marshalling para acceder, manipular y validar contenido XML usando un esquema derivado o elementos de programa. Marshalling: es un proceso de codificacin de un objeto en un medio de almacenamiento, normalmente un fichero. Unmarshalling: proporciona a una aplicacin cliente la capacidad de convertir datos XML a objetos Java JAXB derivados. 5.3.- Introduccin a JAXB. JAXB permite almacenar y recuperar datos en memoria en cualquier formato XML, sin la necesidad de implementar un conjunto especfico de rutinas XML de carga y salvaguarda para la estructura de clases del programa. 5.4.- Funcionamiento de JAXB. Para construir una aplicacin JAXB necesitamos tener un esquema XML. Tras obtener el esquema XML, seguimos los siguientes pasos para construir la aplicacin JAXB: 1. Escribir el esquema: es un documento XML que contiene la estructura que se tomar como indicaciones para construir las clases. 2. Generar los ficheros fuente de Java: para esto usamos el compilador de esquema, ya que ste toma el esquema como entrada de informacin. 3. Construir el rbol de objetos Java: con nuestra aplicacin, se genera el rbol de objetos java, tambin llamado rbol de contenido, que representa los datos XML que son validados con el esquema. Hay dos formas de hacer esto: Instanciando las clases generadas. Invocando al mtodo unmarshall de una clase generada y pasarlo en el documento. El mtodo unmarshall toma un documento XML vlido y construye una representacin de rbol de objetos. 4. Acceder al rbol de contenido usando nuestra aplicacin: ahora podemos acceder al rbol de contenido y modificar sus datos. 5. Generar un documento XML desde el rbol de contenido. Para poder hacerlo tenemos que invocar al mtodo marshall sobre el objeto raz del rbol. Ejemplo de proyecto sencillo con JAXB. Creamos fichero .xsd Vamos a suponer una estructura de un archivo que podra usarse en un almacn distribuidor de medicamentos. El fichero albaran.xsd tiene la estructura que el almacn usa cuando enva un pedido de medicamentos que le ha hecho una farmacia.

public class ModificaAlbaPed { public static void main(String[] args) { try { // Crear una instancia de la clase JAXBContext para poder manipular las clases generadas en el paquete jaxb.albaran // La clase JAXBContext proporciona al cliente un punto de entrada a la API JAXB. Facilita una abstraccin para manejar la informacin generada para implementar las operaciones del JAXB binding framework como unmarshal y marshal // unmarshal: consiste en convertir datos XML en un rbol de objetos Java // marshal: consiste en convertir un rbol de objetos Java a datos XML JAXBContext jaxbContext = JAXBContext.newInstance("jaxb.albaran"); // Crear un objeto de tipo Unmarshaller para convertir datos XML en un rbol de objetos Java Unmarshaller u = jaxbContext.createUnmarshaller(); // La clase JAXBElement representa a un elemento de un documento XML en este caso a un elemento del documento albaran.xml JAXBElement jaxbElement = (JAXBElement) u.unmarshal(new FileInputStream("C:\\albaran.xml")); // El mtodo getValue() retorna el modelo de contenido (content model) y el valor de los atributos del elemento PedidoType pedidoType = (PedidoType) jaxbElement.getValue(); // Obtenemos una instancia de tipo PedidoType para obtener un Objeto de tipo Direccion Direccion direccion = pedidoType.getFacturarA(); // Establecemos los datos direccion.setNombre("Jose Javier"); direccion.setCalle("Zafiro 3"); direccion.setCiudad("Molina"); direccion.setProvincia("Murcia"); direccion.setCodigoPostal(new BigDecimal("30500")); // Crear un objeto de tipo Marshaller para posteriormente convertir un el rbol de objetos Java a datos XML Marshaller m = jaxbContext.createMarshaller(); // El mtodo setProperty(String nombrePropiedad, Object value) recibe en este caso la propiedad "jaxb.formatted.output". Esta propiedad controla si al realizar un marshal, debe formatear el resultado XML con saltos de linea e indentaciones para que las personas podamos leerlo cmodamente. Por defecto su valor es falso es decir el XML creado no est formateado // El argumento value en este caso tiene que ser concretamente de tipo Boolean para indicar si queremos que el resultado XML est formateado o no m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE); // El mtodo marshall(Object elementoJAXB, OutputStream os) recibe un objeto de tipo JAXBElement para que su contenido lo muestre en la salida estndar debido a que este mtodo est sobrecargo, si miramos la documentacin de la API podemos ver como podemos mostrar o escribir el resultado XML de diferentes maneras m.marshal(jaxbElement, System.out); } catch (JAXBException je) { System.out.println(je.getCause()) ; } catch (IOException ioe) { System.out.println(ioe.getMessage()); } } }

6.- Libreras para conversin de documentos XML a otros formatos. En nuestro caso, vamos a optar por una herramienta que permite generar informes de todo tipo en Java de una forma sencilla: JasperReport. 6.1.- Introduccin a JasperReport. JasperReports es una herramienta que consta de un poderoso motor para la generacin de informes. Descarga de JasperReports e integracin en NetBeans. 1. Descargamos y descomprimimos 2. Aadimos a librera: Tools-Libraries.New Library..

6.2.- Disear y compilar la plantilla. Las plantillas de los informes de JasperReports son sencillamente ficheros XML con la extensin .jrxml. Podemos hacer que NetBeans reconozca este tipo de ficheros como XML, para que cuando los editemos en el editor se muestren los mismos cdigos de colores en las etiquetas y dems elementos de la sintaxis de XML.
En la imagen se ilustra cmo conseguirlo: en NetBeans pinchamos en el men Tools, y ah en Options. Ah seleccionamos Miscellaneous, luego la pestaa Files. Entonces pulsamos en el botn New... para aadir la nueva extensin.

Los pasos a seguir para trabajar con JasperReport seran: Paso 1: Disear la plantilla del informe: un fichero .jrxml. El documento de diseo est representado por un archivo XML que mantiene la estructura de un archivo DTD (Document Type Definition) definido por el motor de JasperReports. La generacin de un diseo implica editar un archivo XML validado mediante: <!DOCTYPE jasperReport PUBLIC "-//JasperReports//DTD Report Design//EN" "http://jasperreports.sourceforge.net/dtds/jasperreport.dtd"> Estos documentos XML cuentan con una estructura similar a la de cualquier documento de texto. Fundamentalmente se siguen estas secciones: title Ttulo del informe. pageHeader Encabezado del documento. columnHeader Encabezado de las columnas. detail Detalle del documento. Cuerpo columnFooter Pie de la columna. pageFooter Pie del documento. sumary Cierre del documento. Paso 2: Compilacin: Una vez que se ha realizado el diseo, se compila antes de poder iniciar el proceso de carga de datos. La compilacin se lleva a cabo a travs del mtodo compileReport(). En este proceso, el diseo se transforma en un objeto serializable de tipo net.sf.jasperreports.engine JasperReport, que luego se guarda en disco.

6.3.- Rellenar el informe con datos, exportar el informe.


Paso 3: Rellenar el informe con datos: mediante los mtodos fillReportXXX(), se puede realizar la carga de datos del informe, Como resultado de este proceso, se obtiene un objeto que representa un documento listo para ser impreso, un objeto serializable de tipo JasperPrint. Este objeto puede guardarse en disco para su uso posterior, o bien puede ser impreso, enviado a la pantalla o transformado en PDF, XLS, CSV, etc. Paso 4: Visualizacin.Ahora podemos optar por mostrar un informe por pantalla, imprimirlo, o bien obtenerlo en algn tipo especfico de fichero, como PDF, etc. Para mostrar un informe por pantalla se utiliza la clase JasperViewer, la cual, a travs de su mtodo main(), recibe el informe a mostrar. Para imprimir el informe usaremos los mtodos printReport(), printPage() o printPages(), contenidos en la clase JasperPrintManager. Para exportar los datos a un formato de archivo especfico podemos utilizar los mtodos exportReportXXX(). Ejemplo con JasperReports.

Seguimos desarrollando el ejemplo. Ahora vamos a hacer que obtenga datos de una base de datos. En concreto, de la base de datos derby que se incluye al instalar el jdk.

Manejo de conectores. 1.- Introduccin. Java, mediante JDBC (Java Database Connectivity), permite simplificar el acceso a bases de datos relacionales. 1.1.- El desfase objeto-relacional. consiste en la diferencia de aspectos que existen entre la programacin orientada a objetos y la
base de datos. impedancia Objeto-Relacional, o sea, el conjunto de dificultades tcnicas que surgen cuando una base de datos relacional se usa en conjunto con un programa escrito en POO.

2.- Protocolos de acceso a bases de datos. 2.1.- Arquitectura JDBC. El API JDBC soporta dos modelos de procesamiento para acceso a bases de datos: de dos y tres capas.
En el modelo de dos capas, una aplicacin se comunica directamente a la fuente de datos. En el modelo de tres capas, los comandos se envan a una capa intermedia de servicios, la cual enva los comandos a la fuente de datos. El API JDBC viene distribuido en dos paquetes: java.sql, dentro de J2SE. javax.sql, extensin dentro de J2EE. 2.2.- Conectores o Drivers. Un conector o driver es un conjunto de clases encargadas de implementar los interfaces del API y acceder a la base de datos. Hay cuatro tipos de drivers JDBC: Tipo 1, Tipo 2, Tipo 3 y Tipo 4, que veremos a continuacin. Cdigo de la estructura para conectarnos, ejecutar consulta y procesar resultados. // Establece la conexin Connection con = DriverManager.getConnection ("jdbc:odbc:miBD", "miLogin", "miPassword" ); // Ejecuta la consulta Statement stmt = (Statement) con.createStatement(); ResultSet rs = stmt.executeQuery("SELECT nombre, edad FROM Empleados"); // Procesa los resultados while (rs.next()) { String nombre = rs.getString("nombre"); int edad = rs.getInt("edad"); }

2.3.- Conectores tipo 1 y tipo 2.


Los conectores tipo 1 se denominan tambin JDBC-ODBC Bridge (puente JDBC-ODBC). Los conectores tipo 2 se conocen tambin como: API nativa. Convierten las llamadas JDBC a llamadas especficas de la base de datos para bases de datos como SQL Server, Informix, Oracle, o Sybase. los drivers tipo 2 no pueden usarse para Internet.

2.4.- Conectores tipo 3 y tipo 4.


Tipo 3: JDBC-Net pure Java driver. Tiene una aproximacin de tres capas. Tipo 4: Protocolo nativo. En este caso se trata de conectores que convierten directamente las llamadas JDBC al protocolo de red usando por el sistema gestor de la base de datos. Un ejemplo de este tipo de conector es Oracle Thin. 3.- Conexin a una base de datos. En Java, para establecer una conexin con una base de datos podemos utilizar el mtodo getConnection() de la clase DriverManager. La ejecucin de este mtodo devuelve un objeto Connection que representa la conexin con la base de datos. Si no se encuentra ningn conector adecuado, se lanza una SQLException

3.1.- Instalar el conector de la base de datos. Para que podamos ejecutar el cdigo anterior, necesitamos instalar el conector
de la base de datos. En la siguiente presentacin vamos a ver cmo descargarnos el conector que necesitamos para trabajar con MySQL. Como vers, tan slo consiste en descargar un archivo, descomprimirlo y desde NetBeans aadir el fichero .jar que constituye el driver que necesitamos. Instalar conector JDBC para MySQL: En esta pagina lo descargamos: http://www.mysql.com/downloads/connector/j/

En la pantalla que aparece despus, pinchamos en la parte de abajo para poder seleccionar los servidores de descarga donde se aloja el conector JDBC. Ahora, elegimos uno de lo servidores que aparecen y pinchamos en FTP En NetBeans, situndonos en el nombre el proyecto pulsamos el botn derecho del ratn.En el men contextual que aparece seleccionamos Properties.Seleccionamos el nodo de las Libreras del proyecto.Pinchamos en el botn Add JAR/Folder.Buscamos y elegimos el fichero comentado anteriormente, el .jar.Tan solo queda pulsar Ok y hemos acabado.

3.2.- Pool de conexiones. El proceso de creacin y destruccin de una conexin a una base de datos es costoso e influye sensiblemente en el rendimiento de una aplicacin. Es mejor en estos casos, por tanto, abrir una o ms conexiones y mantenerlas abiertas. La versin 3.0 de JDBC proporciona un pool de conexiones que funciona de forma transparente. El cdigo bsico para conectarnos a una base de datos con pool de conexiones transparente a travs de JNDI podra ser: //Initial Context es el punto de entrada para comenzar a explorar un espacio de nombres. javax.naming.Context ctx = new InitialContext(); dataSource = (DataSource) ctx.lookup("java:comp/env/jdbc/Basededatos"); Cada vez que necesitamos realizar una operacin tendremos que escribir el siguiente cdigo para obtener una conexin lgica: connection = dataSource.getConnection(); Cuando hayamos finalizado la operacin entonces cerraremos la conexin lgica con el siguiente cdigo: connection.close(); 4.- Creacin de la base de datos. 5.- Operaciones: ejecucin de consultas.
Podemos utilizar los siguientes tipos de sentencias: Statement: para sentencias sencillas en SQL. PreparedStatement: para consultas preparadas, como por ejemplo las que tienen parmetros. CallableStatement: para ejecutar procedimientos almacenados en la base de datos. El API JDBC distingue dos tipos de consultas: Consultas: SELECT Actualizaciones: INSERT, UPDATE, DELETE, sentencias DDL.

5.1.- Ejemplo: consultas con MS-Access.


En primer lugar tenemos que definir la fuente de datos ODBC.

instalar el driver JDBC. Dentro del cdigo se carga el driver antes de acceder a la base de datos: Class.forName("jdbc:odbc:admdb"); realizar la conexin a la base de datos para comenzar a trabajar con ella. Connection con = DriverManager.getConnection("jdbc:odbc:admdb"); Las consultas que se realizan a una base de datos se realizan utilizando objetos de las clases Statement y PreparedStatement. Estos objetos se crean a partir de una conexin. Statement stmt = con.createStatement(); La clase Statement contiene los mtodos executeQuery y executeUpdate para realizar consultas y actualizaciones. As por ejemplo, para obtener los nombres de los medicamentos que tenemos en la tabla medicamentos, de la base de datos farmacia.mdb que creamos anteriormente, tendramos que emplear la sentencia: ResultSet rs = stmt.executeQuery("SELECT nombre from medicamentos"); El mtodo executeQuery devuelve un objeto ResultSet para poder recorrer el resultado de la consulta utilizando un cursor. El mtodo next se emplea para hacer avanzar el cursor. Para obtener una columna del registro utilizamos los mtodos get. Hay un mtodo get para cada tipo bsico Java y para las cadenas. while (rs.next()) String usuario = rs.getString("nombre"); Comentar que un mtodo interesante del cursor es wasNull que nos informa si el ltimo valor ledo con un mtodo get es nulo. Respecto a las consultas de actualizacin, executeUpdate, retornan el nmero de registros insertados, registros actualizados o eliminados, dependiendo del tipo de consulta que se trate. import java.sql.Connection; import java.sql.DriverManager; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; public class Main { public static void main(String[] args) { try {

// Cargar el driver de Microsoft Access Class.forName("sun.jdbc.odbc.JdbcOdbcDriver"); // Cadena de conexin para conectar con Access String connectionUrl = "jdbc:odbc:admdb" ; // Obtener la conexin Connection con = DriverManager.getConnection(connectionUrl); // La clase Statement contiene los mtodos executeQuery y executeUpdate para realizar consultas y actualizaciones Statement stmt = con.createStatement(); //El mtodo executeQuery devuelve un objeto ResultSet para poder recorrer el resultado de la consulta utilizando un cursor. // Esta consulta obtiene todos los datos, todos los campos, )debido al *), almacenados en la tabla medicamentos. ResultSet rs = stmt.executeQuery("SELECT * from medicamentos"); // Mientras queden datos while (rs.next()) { // Imprimir en la consola String codigo = rs.getString("codigo"); String nombre = rs.getString("nombre"); String precio = rs.getString("precio"); String pvp = rs.getString("pvp"); String unidades = rs.getString("unidades"); System.out.println(codigo + "---" + nombre + "--" +precio+ "--" +pvp+ "--" +unidades); } } catch (SQLException e) { System.out.println("SQL Exception: "+ e.toString()); } catch (ClassNotFoundException cE) { System.out.println("Excepcin: "+ cE.toString()); } }} 5.2.- Consultas preparadas. Las consultas preparadas estn representadas por la clase PreparedStatement. Son consultas precompiladas, por lo que son ms eficientes, y pueden tener parmetros. Una consulta se instancia del modo que vemos con un ejemplo: PreparedStatement pstmt = con.preparedStatement("SELECT * from medicamentos"); Si hay que emplear parmetros en una consulta, se puede hacer usando el carcter ?. Por ejemplo, para realizar una consulta de un medicamento que tenga un cdigo determinado, haramos la consulta siguiente: PreparedStatement pstmt = con.preparedStatement("SELECT * from medicamentos WHERE codigo = ? "); Establecemos los parmetros de una consulta utilizando mtodos set que dependen del tipo SQL de la columna. As, le decimos que el primer parmetro, que es el nico que tiene esta consulta, es 712786: pstmt.setString(1, "712786"); Finalmente, ejecutamos la consulta utilizando el mtodo executeQuery() o executeUpdate(), ambos sin parmetros, dependiendo del tipo de consulta. Ejemplo: public class Actualizacion{ private PreparedStatement sentencia; public void prepararInsercion(){ String sql = "insert into personas values ( ?, ? ,? )"; sentencia = conexion.prepareStatement(sql); } public void insertarPersona(String nombre, direccin, telefono) { sentencia.setString(1, nombre); sentencia.setString(2, direccion); sentencia.setString(3, telefono); sentencia.executeUpdate(); }}

6.- Ejecucin de procedimientos almacenados en la base de datos.


Adems, estos procedimientos suelen ser de dos clases: Procedimientos almacenados. Funciones, las cuales devuelven un valor que se puede emplear en otras sentencias SQL. Un procedimiento almacenado tpico tiene: Un nombre. Una lista de parmetros. Unas sentencias SQL.

6.1.- Ejecutando procedimentos almacenados en MySQL.


A continuacin, vamos a realizar un procedimiento almacenado en MySQL, que simplemente insertar datos en la tabla clientes. -Si no tenemos creada la tabla de clientes, la creamos. Por simplicidad, en este ejemplo, trabajamos sobre la base de datos que viene por defecto en MySQL, el esquema denominado: test. Para crear la tabla de clientes, el script correspondiente es: delimiter $$ CREATE TABLE `clientes` ( `Cod_Cliente` int(3) NOT NULL DEFAULT '0', `Nombre` tinytext, `Telefono` tinytext, PRIMARY KEY (`Cod_Cliente`) ) ENGINE=InnoDB DEFAULT CHARSET=latin1$$ -Creamos el procedimiento almacenado en la base de datos. Sera tan fcil como lo que ves en el siguiente enlace: DELIMITER $$ CREATE DEFINER=`root`@`localhost` PROCEDURE `insertaCliente`(IN Cod_Cliente INTEGER, IN Nombre TinyText,IN Telefono TinyText ) BEGIN INSERT INTO clientes VALUES (Cod_Cliente, Nombre, Telefono); END

-Crear la clase Java para desde aqu, llamar al procedimiento almacenado: public class inserConProcAlma { public static void main(String[] args) { try { // Cargar el driver de mysql Class.forName("com.mysql.jdbc.Driver"); // Cadena de conexin para conectar con MySQL en localhost,seleccionar la base de datos llamada test con usuario y contrasea del servidor de MySQL: root y admin String connectionUrl = "jdbc:mysql://localhost/test?" + "user=root&password=admin"; // Obtener la conexin Connection con = DriverManager.getConnection(connectionUrl); // El procedimiento almacenado tendr tres parmetros CallableStatement prcProcedimientoAlmacenado = con.prepareCall("{ call insertaCliente(?, ?,?) }"); // cargar parametros en el procedimiento almacenado prcProcedimientoAlmacenado.setInt("Cod_Cliente", 765); prcProcedimientoAlmacenado.setString("Nombre", "Antonio Prez") ; prcProcedimientoAlmacenado.setString("Telefono", "950121314") ; // ejecutar el procedimiento prcProcedimientoAlmacenado.execute(); } catch (SQLException e) { System.out.println("SQL Exception: "+ e.toString()); } catch (ClassNotFoundException cE) { System.out.println("Excecin: "+ cE.toString()); } }} Si hemos definido la tabla correctamente, con su clave primaria, y ejecutamos el programa, intentando insertar una fila igual que otra insertada, o sea, con la misma clave primaria, obtendremos un mensaje al capturar la excepcin de este tipo: SQL Exception: com.mysql.jdbc.exceptions.jdbc4.MySQLIntegrityConstraintViolationException: Duplicate entry '765' for key 'PRIMARY' 7.- Transacciones. Cuando tenemos una serie de consultas SQL que deben ejecutarse en conjunto, con el uso de transacciones podemos asegurarnos de que nunca nos quedaremos a medio camino de su ejecucin. 7.1.- Commit y Rollback. Una transaccin tiene dos finales posibles, COMMIT o ROLLBACK. Si se finaliza correctamente y sin problemas se har con COMMIT, con lo que los cambios se realizan en la base de datos, y si por alguna razn hay un fallo, se deshacen los cambios efectuados hasta ese momento, con la ejecucin de ROLLBACK. Por defecto, al menos en MySQL o con Oracle, en una conexin trabajamos en modo autocommit con valor true. Eso significa que cada consulta es una transaccin en la base de datos. Por tanto, si queremos definir una transaccin de varias operaciones, estableceremos el modo autocommit a false con el mtodo setAutoCommit de la clase Connection. Puedes ver un ejemplo sencillo de cmo se puede utilizar commit y rollback: tras las operaciones se realiza el commit, y si ocurre una excepcin, al capturarla realizaramos el rollback. BEGIN SET AUTOCOMMIT OFF update cuenta set saldo=saldo + 250 where dni=12345678-L; update cuenta set saldo=saldo - 250 where dni=89009999-L; COMMIT; EXCEPTION WHEN OTHERS THEN ROLLBACK ; END;

8.- Excepciones y cierre de conexiones. 8.1.- Excepciones. Cuando se produce un error durante la ejecucin de un programa, se genera un objeto asociado a esa excepcin.
try { // Bloque de instrucciones del try }catch (FileNotFoundException fnfe){ // Bloque para excepcin por fichero no encontrado }catch(IOException ioe){ // Bloque para excepcin por error de entrada salida }catch(SQLException sqle){ // Bloque para excepcin por error con SQL }catch(Exception e){ }finally{ //Instrucciones finales para, por ejemplo, limpieza }

8.2.- Cierre de conexiones. Resulta totalmente conveniente cerrarlas con el mtodo close cuando ya no se utilizan.

Mapeo objeto relacional. 1.- Concepto de Mapeo objeto-relacional(ORM). Es una tcnica de programacin que se utiliza con el propsito de convertir
datos entre el utilizado en un lenguaje de programacin orientado a objetos y el utilizado en una base de datos relacional, gracias a la la persistencia. traducir los objetos a formas que puedan ser almacenadas en bases de datos preservando las propiedades de los objetos y sus relaciones; estos objetos se dice entonces que son persistentes. 2.- Herramientas ORM. Caractersticas y herramientas ms utilizadas. Object Relational Mapping (ORM) es la herramienta que nos sirve para transformar representaciones de datos de los Sistemas de Bases de Datos Relacionales, a representaciones (Modelos) de objetos. En el modelo relacional, cada fila en la tabla se mapea a un objeto y cada columna a una propiedad. 2.1.- Caractersticas. Una herramienta ORM permite tomar un objeto Java y hacerlo persistente, carga el objeto de la base de datos a memoria y permite hacer consultas a las tablas de la base de datos. Ventajas de ORM. Ayudan a reducir el tiempo de desarrollo de software. Abstraccin de la base de datos. Reutilizacin. Permiten persistir objetos a travs de un mtodo Orm.Save y generar el SQL correspondiente. Permiten recuperar los objetos persistidos a travs de un mtodo Orm.Load. Lenguaje propio para realizar las consultas. Independencia de la base de datos. Incentivan la portabilidad y escalabilidad de los programas de software. Desventajas de ORM. Tiempo utilizado en el aprendizaje. Menor rendimiento (aplicaciones algo ms lentas). Sistemas complejos.

2.2.- Herramientas ORM ms utilizadas.


Hibernate: para la plataforma Java. Utiliza archivos declarativos (XML) Java Persistence Api (JPA): es una especificacin de Sun Microsystems para la persistencia de objetos Java a cualquier base de datos relacional. iBatis: iBatis es un framework de persistencia desarrollado por la Apache software Foundation. 3.- Instalacin y configuracin de Hibernate. El archivo de configuracin de Hibernate recibe el nombre de Hibernate.cfg.xml y contiene informacin sobre la conexin de la base de datos y otras propiedades. 4.- Ficheros de configuracin y mapeo. Estructura y propiedades. Para utilizar Hibernate necesitamos tener una base de datos relacional instalada en NetBeans. La base de datos Sakila es una muestra gratuita disponible, como plugin, en NetBeans. 4.1.- Ficheros de configuracin. Propiedades. El archivo de configuracin de Hibernate es el Hibernate.cfg.xml y contiene informacin sobre la conexin de base de datos, las asignaciones de recursos y otras propiedades de conexin.

Las propiedades ms importantes del fichero Hibernate.cfg.xml son: Hibernate.dialect: Dialecto o lenguaje empleado. Por ejemplo, MySQL. Hibernate.connection.driver_class. Driver utilizado para la conexin con la base de datos. Hibernate.connection.url. Direccin de la base de datos con la que se va a conectar Hibernate. Hibernate.connection.username. Nombre del usuario que va a realizar la extraccin de informacin. Por defecto, el nombre de usuario es root. Hibernate.connection.password. Contrasea el root. Hibernate.show_sql. Para mostrar la herramienta. Por defecto, su valor es true. 4.2.- Ficheros de mapeo. Estructura, elementos y propiedades. Hibernate utiliza ficheros de mapeo para relacionar tablas con objetos Java, estos ficheros estn en formato XML y que tienen extensin .hbm.xml. Para extraer un tabla concreta de la base de datos, la sintaxis en el mapeo requiere definir el POJO Nombre_Clase.hbm.xml, donde nombre_clase se corresponder con el nombre la tabla que queremos extraer y donde se describe cmo se relacionan clases y tablas y propiedades y columnas. Podemos utilizar la ingeniera inversa para crear archivos de mapeo basados en tablas de la base de datos que seleccionemos. El archivo de ingeniera inversa es Hibernate.reveng.xml. Mediante el asistente de NetBeans, seleccionamos Nuevo Mapeo en Hibernate y rellenamos los campos que nos piden, en funcin de la informacin que nos interese extraer de la base de datos. De esta manera, NetBeans genera un POJO nombre_clase.java (siendo nombre_clase aquella tabla cuya informacin nos interesa extraer de la base de datos) con todos los campos necesarios.

5.- Mapeo de colecciones, relaciones y herencia. 1. Mapeo de colecciones. Hay bastantes rangos de mapeos que se pueden generar para colecciones que cubran diversos modelos
relacionales.

2. Mapeo de relaciones. Para mapear las relaciones, se usan los identificadores de objetos (OID). Son la llave primaria de la tabla relacionada y se agregan como una columna ms en la tabla donde se quiere establecer la relacin. 3. Mapeo de herencia. Para el caso de la herencia se presenta el problema que las base de datos relacionales no la soportan. As es que somos nosotros quienes debemos modelar como se ver la herencia en el modelo relacional. 6.- Clases persistentes. Las clases persistente son clases en una aplicacin que nos van a servir para representar entidades de la base de datos. Para poder indicar las clases y atributos que son persistentes, se utiliza un fichero de configuracin XML, que se denomina descriptor de persistencia. 7.- Sesiones; estados de un objeto. Para poder utilizar la persistencia en Hibernate es necesario definir un objeto Session utilizando la clase SesssionFactory. Los estados en los que se puede encontrar un objetos son: Transitorio (Transient). En este estado estar un objeto recin creado que no ha sido enlazado con el gestor de persistencia. Persistente: Ente este caso el objeto est enlazado con la sesin. Todos los cambios que se realicen ser persistentes. Disociado (Detached): En este caso nos encontramos con un objeto persistente que sigue en memoria despus de que termine la sesin. En este caso existe en Java y en la base de datos. Borrado (Removed): En esta caso el objeto est marcado para ser borrado de la base de datos. Existe en la aplicacin Java y se borrar de la base de datos al terminar la sesin. 8.- Carga, almacenamiento y modificacin de objetos. Para cargar un objeto de acceso a datos en la aplicacin Java, el mtodo load() de la clase Session suministra un mecanismo para capturar una instancia persistente, si conocemos su identificador. El mtodo load() acepta un objeto Class, y cargar el estado de una nueva instancia de esa clase, inicializada en estado persistente. El mtodo load() lanzar una excepcin irrecuperable si no existe la fila de base de datos correspondiente. Si no se est seguro de que exista una fila correspondiente, debe usarse el mtodo get(), el cual consulta la base de datos inmediatamente y devuelve null si no existe una fila correspondiente. 8.1.- Almacenamiento y modificando de objetos persistentes. Para almacenar objetos persistentes se proceso siguiendo los siguientes pasos: 1. Se instancia un objeto nuevo (estado transitorio). 2. Se obtiene una sesin y se comienza la transaccin, inicializando el contexto de persistencia. 3. Una vez obtenida da la sesin, se llama al mtodo save(), el cual introduce el objeto en el contexto de persistencia. Este mtodo devuelve el identificador del objeto persistido. 4. Para que los cambios sean sincronizados en las bases de datos, es necesario realizar el commit de la transaccin. Dentro del objeto sesin se llama al mtodo flush(). Es posible llamarlo explcitamente. En este momento, se obtiene la conexin JDBC a la bases de datos para poder ejecutar la oportuna sentencia. 5. Finalmente, la sesin se cierra, con el objeto de liberar el contexto de persistencia, y por tanto, devolver la referencia del objeto creado al estado disociado. Para borrar objetos persistentes, podemos ejecutar Session.delete(), que quitar el estado de un objeto de la base de datos. 9.- Consultas SQL. Usando Hibernate, la ejecucin de consultas SQL nativas se controla por medio de la interfaz SQLQuery, la cual se obtiene llamando a Session.createSQLQuery().La consulta SQL ms bsica es para obtener a una lista de escalares (valores). sess.createSQLQuery("SELECT * FROM Personas").list(); sess.createSQLQuery("SELECT ID,NOMBRE, EDAD FROM PERSONAS").list(); Estas retornarn una lista de objetos arrays (Object[]) con valores escalares para cada columna en la tabla PERSONAS. Otro tipo de consulta ms compleja, es la consulta de entidades. Para obtener los objetos entidades desde una consulta sql nativa, se utiliza por medio de addEntity(). sess.createSQLQuery("SELECT * FROM PERSONAS").addEntity(Persona.class); sess.createSQLQuery("SELECT ID,NOMBRE,EDAD FROM PERSONAS").addEntity(Persona.class); 10.- Lenguajes propios de la herramienta ORM. Hibernate utiliza un lenguaje de consulta potente (HQL) que se parece a SQL. HQL es completamente orientado a objetos y comprende nociones como herencia, polimorfismo y asociacin. Entre las caractersticas ms importantes de HQL.

Soporte completo para operaciones relacionales: HQL permite representar consultas SQL en forma de objetos. HQL usa clases y atributos o propiedades en vez de tablas y columnas. Regresa sus resultados en forma de objetos: Las consultas realizadas usando HQL regresan los resultados de las mismas en la forma de objetos o listas de objetos, que son ms fciles de usar. Consultas Polimrficas: Podemos declarar el resultado usando el tipo de la superclase e Hibernate se encargara de crear los objetos adecuados de las subclases correctas de forma automtica. Soporte para caractersticas avanzadas: HQL contiene muchas caractersticas avanzadas que son muy tiles y que no siempre estn presentes en todas las bases de datos, o no es fcil usarlas, como paginacin, fetch joins con perfiles dinmicos, inner y outer joins, etc. Adems soporta proyecciones, funciones de agregacin (max, avg), y agrupamientos, ordenamientos, y subconsultas. Independiente del manejador de base de datos: Las consultas escritas en HQL son independientes de la base de datos (siempre que la base de datos soporte la caracterstica que estamos intentando utilizar ^

10.1.- Lenguaje HQL.


Clausula from: la siguientes sera una consulta que mostrara todos los datos de una tabla de nombre Alumnos: from Alumnos Clusula select: La clusula select escoge qu objetos y propiedades devolver en el conjunto de resultados de la consulta. Un ejemplo de consulta podra ser select alumno.nombre from Alumnos alumno where alumno.nombre like 'A%' La clusula where: La clusula where nos permite refinar la lista de instancias retornadas. Si no existe ningn alias, puede referirse a las propiedades por nombre: from Alumnos where nombre='Francisco'. Si existe un alias, usaremos un nombre de propiedad calificado: from Alumnos as alumnos where alumnos.nombre='Francisco'. Esto retorna instancias de Alumnos llamados "Francisco". Funciones de agregacin. Las consultas HQL pueden retornar resultados de funciones de agregacin sobre propiedades: select avg(alumnos.nota), sum(alumnos.nota), max(alumnos.nota), count(alumnos) from Alumnos alumnos. Expresiones. Las expresiones utilizadas en la clusula where incluyen lo siguiente: operadores matemticos, operadores de comparacin binarios, operadores lgicos , parntesis ( ) que indican agrupacin, funciones Java, etc. La clusula order by. La lista retornada por una consulta se puede ordenar por cualquier propiedad de una clase retornada o componentes. La palabra asc o desc opcionales indican ordenamiento ascendente o descendente respectivamente. La clusula group by. Una consulta que retorna valores agregados se puede agrupar por cualquier propiedad de una clase retornada o componentes: Subconsultas. Para bases de datos que soportan subconsultas, Hibernate soporta subconsultas dentro de consultas. Una subconsulta se debe encerrar entre parntesis (frecuentemente por una llamada a una funcin de agregacin SQL). Incluso se permiten subconsultas correlacionadas (subconsultas que se refieren a un alias en la consulta exterior).

public static String CONSULTA_BASADA_EN_NOMBRE="from Actor a where a.firstName like '"; public static String CONSULTA_BASADA_EN_APELLIDO="from Actor a where a.lastName like '";

private void ejecutaConsultaBasadaEnNombre(){ ejecutaHQLConsulta(CONSULTA_BASADA_EN_NOMBRE+txtNombre.getText()+"%'"); } private void ejecutaConsultaBasadaEnApellidos(){ ejecutaHQLConsulta(CONSULTA_BASADA_EN_APELLIDO+txtApellidos.getText()+"%'"); } private void ejecutaHQLConsulta(String hql){ try{ Session session=HibernateUtil.getSessionFactory().openSession(); session.beginTransaction(); Query consulta=session.createQuery(hql); List resultList=consulta.list(); mostrarResultado(resultList); session.getTransaction().commit(); } catch (HibernateException he){ he.printStackTrace(); } }

private void btConsultaActionPerformed(java.awt.event.ActionEvent evt) { // TODO add your handling code here: if(!txtNombre.getText().trim().equals("")){ ejecutaConsultaBasadaEnNombre(); }else if(!txtApellidos.getText().trim().equals("")){ ejecutaConsultaBasadaEnApellidos(); } }

private void mostrarResultados(List resuList){ Vector<String> tableHeaders=new Vector<String>(); Vector tableData=new Vector(); tableHeaders.add("Actor id"); tableHeaders.add("Nombre"); tableHeaders.add("Apellidos"); tableHeaders.add("Actualizado"); for (Object o:resuList){ Actor actor=(Actor) o; Vector <Object> oneRow=new Vector<Object>(); oneRow.add(actor.getActorId()); oneRow.add(actor.getFirstName()); oneRow.add(actor.getLastName()); oneRow.add(actor.getLastUpdate()); tableData.add(oneRow); } tbResultados.setModel(new DefaultTableModel(tableData, tableHeaders)); }

11.- Gestin de transacciones. Un transaccin es un conjunto de rdenes que se ejecutan formando un unidad de trabajo, en forma indivisible o atmica. Session session = HibernateUtil.getSessionFactory().openSession(); Transaction tx = null; try { tx = session.beginTransaction(); // Utilizar la Session para saveOrUpdate/get/delete/...tx.commit(); } catch (Exception e) { if (tx != null) { tx.rollback(); throw e; } } finally { session.close(); }// Al finalizar la aplicacin ...HibernateUtil.shutdown( ); Cuando se crea el objeto Session , se le asigna la conexin de la base de datos que va a utilizar. Una vez obtenido el objeto Session , se crea una nueva unidad de trabajo ( Transaction) utilizando el mtodo beginTransaction. Dentro del contexto de la transaccin creada, se pueden invocarlos mtodos de gestin de persistencia proporcionados por el objeto Session, para recuperar, aadir, eliminar o modificar el estado de instancias de clases persistentes. Tambin se pueden realizar consultas. Si las operaciones de persistencia no han producido ninguna excepcin, se invoca el mtodo commit de la unidad de trabajo para confirmar los cambios realizados. En caso contrario, se realiza un rollback para deshacer los cambios producidos. Sobre un mismo objeto Session pueden crearse varias unidades de trabajo. Finalmente se cierra el objeto Session invocando su mtodo close.

Bases de datos objeto-relacionales y orientadas a objetos. 1.- Introduccin. Las Bases de Datos Orientadas a Objetos (BDOO) o Bases de Objetos se integran directamente y sin problemas con
las aplicaciones desarrolladas en lenguajes orientados a objetos, ya que soportan un modelo de objetos puro y son ideales para almacenar y recuperar datos complejos permitiendo a los usuarios su navegacin directa (sin un mapeo entre distintas representaciones). Las Bases de Datos Objeto-Relacionales (BDOR) son bases de datos relacionales que han evolucionado hacia una base de datos ms extensa y compleja , incorporando conceptos del modelo orientado a objetos. Pero en estas bases de datos an existe un mapeo de objetos subyacente, que es costoso y poco flexible, cuando los objetos y sus interacciones son complejos. 2.- Caractersticas de las bases de datos orientadas a objetos. La principal caracterstica de las BDOO es que soportan un modelo de objetos puro y que el lenguaje de programacin y el esquema de la base de datos utilizan las mismas definiciones de tipos. Soportan las caractersticas propias de la Orientacin a Objetos. Identificador de objeto (OID). Cada objeto tiene un identificador. Jerarqua y extensin de tipos. Se pueden definir nuevos tipos basndose en otros tipos predefinidos. Objetos complejos. Acceso navegacional de datos. Gestin de versiones. 2.1.- Ventajas e inconvenientes.Ventajas: la transparencia, Gran capacidad de modelado. Flexibilidad. Soporte para el manejo de objetos complejos. Alta velocidad de procesamiento. Extensibilidad. Mejora los costes de desarrollo, Facilitar el control de acceso y concurrencia, Funcionan de forma eficiente en entornos cliente/servidor y arquitecturas distribuidas. Desventajas: Carencia de un modelo de datos universal. Falta de estndares. Complejidad. Competencia de otros modelos. Difcil optimizacin de consultas.

3.- Gestores de bases de datos orientadas a objetos.


Db4o de Versant. Es una BDOO Open Source para Java y .NET. Se distribuye bajo licencia GPL. Matisse. Es un SGBOO basado en la especificacin ODMG, proporciona lenguajes para definicin y manipulacin de objetos, as como interfaces de programacin para C, C++, Eiffel y Java. ObjectDB. Es una BDOO que ofrece soporte para Java, C++, y Python entre otros lenguajes. No es un producto libre, aunque ofrecen versiones de prueba durante un periodo determinado. EyeDB. Es un SGBOO basado en la especificacin ODMG, proporciona lenguajes para definicin y manipulacin de objetos, e interfaces de programacin para C++ y Java. Se distribuye bajo licencia GNU y es software libre. Neodatis, ObjectStore y GemStone. Son otros SGBDOO. 3.1.- Objetos simples y objetos estructurados. Un objeto de tipo simple u objeto simple es aquel que no contiene a otros objetos y por tanto posee una estructura de un solo nivel de profundidad en este sentido.Un objeto de tipo estructurado u objeto estructurado incluye entre sus componentes a otros objetos. Entre un objeto y sus componentes de cada nivel, existen dos tipos de referencia: Referencia de propiedad. Se aplica cuando los componentes de un objeto se encapsulan dentro del propio objeto y se consideran, por tanto, parte de ese objeto. Relacin es-parte-de. Referencia de asociacin. Se aplica cuando entre los componentes del objeto estructurado existen objetos independientes, pero es posible hacer referencia a ellos desde el objeto estructurado. Relacin est-asociado-con. Una relacin uno a muchos se representa mediante un objeto tipo coleccin (List, Set, etc.). 3.2.- Instalacin del gestor de objetos Db4o. descargar de www.db4o.com

4.- El API de la base de objetos.


Los principales paquetes del API de Db4o son los siguientes: com.db4o. Paquete principal (core) de la Base de Objetos. com.db4o.query. Paquete con funcionalidades de consulta. om.db4o.config. Paquete con funcionalidades de configuracin. La documentacin del API viene en formato JavaDoc y la puedes encontrar en el directorio /doc/api del fichero .zip descargado y descomprimido. Siempre que trabajemos con bases de objetos Db4o utilizaremos el interface ObjectContainer, puesto que es quien representar a la base de objetos, sea embebida o no. 4.1.- Apertura y cierre de conexiones. En general, la conexin de una aplicacin Java con una base de objetos se podr realizar va: JDBC. El API proporcionado por el propio gestor de objetos. Abrir conexin. Podemos utilizar las siguientes clases: Db4oEmbedded. Es una clase que hereda de java.lang.Object y proporciona mtodos estticos como openFile() para abrir una instancia de la base de datos en modo embebido. ObjectServer. Es un interfaz que permite trabajar con una base de datos db4o en modo cliente-servidor. Una vez abierta la base de datos como servidor mediante Db4o.openServer(), el mtodo openClient() del interfaz ObjectServer permitir abrir conexiones cliente directamente en memoria o bien mediante TCP/IP. Cerrar conexin. Para ello utilizaremos el mtodo close() de la interfaz ObjectContainer.

package congreso; public class ponente { private String nif; private String nombre; private String email; private float cache; //constructores public ponente() { this.nif=null; this.nombre = null; this.email = null; this.cache = 0; } public ponente(String ni, String n, String e) { this.nif=ni; this.nombre = n; this.email = e; this.cache = -1; //cach no asignado } public ponente(String ni, String no, String e, float c) { this.nif=ni; this.nombre = no; this.email = e; this.cache = c; } //mtodos bsicos para asignar y obtener valores de atributos public void setNif(String n) { this.nif = n; } public String getNif() { return this.nif;

} public void setNombre(String n) { this.nombre = n; } public String getNombre() { return this.nombre; } public void setEmail(String e) { this.email = e; } public String getEmail() { return this.email; } public void setCache(float c) { this.cache = c; } public float getCache() { return this.cache; } @Override //comportamiento del mtodo toString heredado de la superclase Objet //Devuelve los atributos de un objeto ponente public String toString() { if (this.cache != -1) { return this. nif+" "+this.nombre+" "+this.email+" Cach:"+this.cache; } else { return this.nif+" "+this.nombre +" "+this.email; } } }

package congreso; import com.db4o.Db4oEmbedded; import com.db4o.ObjectContainer; public class Main { public static void main(String[] args) { // TODO code application logic here ObjectContainer db = Db4oEmbedded.openFile(Db4oEmbedded.newConfiguration(),"congreso.db4o"); //La base de datos fsica es el fichero "congreso.db4o" almacenado en la //carpeta raz del proyecto creado try { almacenarPonentes(db); } finally { db.close(); //cerrar la conexin a la base de datos } }

//Mtodo para almacenar datos en la Base de Objetos. public static void almacenarPonentes(ObjectContainer db) { //se crean cuatro objetos tipo alumno con valores asignados ponente p1 = new ponente("11A", "Antonio Camaco", "acamacho@gmail.es", 300); ponente p2 = new ponente("22B","Isabel Prez", "iperez@hotmail.es", 100); ponente p3 = new ponente("33C","Ana Navarro", "anavarro@yahoo.com", 200); ponente p4 = new ponente("44D","Pedro Snchez", "psanchez@mixmail.com", 90); //Persistir Objetos: almacenamos los objetos con el mtodo store() db.store(p1); db.store(p2); db.store(p3); db.store(p4); }

4.2.- Consultas a la base de objetos.


A una BDOO se podrn realizar consultas mediante: Un lenguaje de consultas como OQL, si el gestor est basado en el estandar ODMG e incluye sentencias del tipo SQL. El API proporcionado por el propio sistema gestor de bases de datos orientadas a objetos. Los tres sistemas de consulta que proporciona Db4o basados en el API del propio gestor, son los siguientes: Consultas por ejemplo. Query By Example (QBE). Es la forma ms sencilla y bsica de realizar cosultas, pero tienen bastantes limitaciones. Consultas nativas. Native Queries (NQ). Es la interface principal de consultas de la base de objetos. Permiten realizar un filtro contra todas las instancias de la base de objetos. Consultas SODA. Simple Object Data Access (SODA). Permite generar consultas dinmicas.

public static void consultarPonentes(ObjectContainer db) { ponente p = new ponente(null, null, null, 0); //prototipo de bsqueda ObjectSet res = db.queryByExample(p); //realizacin de consulta mostrarConsulta(res);//obtencin de resultados }

//Mtodo para mostrar objetos recuperados de la Base de Objetos public static void mostrarConsulta(ObjectSet resul) { System.out.println("Recuperados " + resul.size() + " Objetos"); while (resul.hasNext()) { System.out.println(resul.next()); } }

//consulta de un ponente en concreto. Consultar ponentes de cache 200. public static void consultarPonente200(ObjectContainer db) { ponente p = new ponente(null, null, null, 200); ObjectSet res = db.queryByExample(p); mostrarConsulta(res); } //consulta de ponentes por nombre. Al mtodo se le pasa el parmetro nomb public static void consultarPonentePorNombre(ObjectContainer db, String nomb) { ponente p = new ponente(null, nomb, null, 0);//prototipo de bsqueda ObjectSet res = db.queryByExample(p); mostrarConsulta(res); }

//Mtodo para consultar todos los ponentes public static void consultaSODAponentes(ObjectContainer db) { Query query = db.query();//declara un objeto Query //indica la clase a la que se aplicarn restricciones query.constrain(ponente.class); ObjectSet result = query.execute(); //Ejecuta la consulta mostrarConsulta(result);//muestra los resultados de la consulta }

//Consulta SODA de todos los ponentes con cach 200 public static void consultaSODAcache200(ObjectContainer db) { Query query = db.query(); //se declara objeto tipo Query() query.constrain(ponente.class); //clase a la que se aplican restricciones //establece restriccin del valor 200 para cache query.descend("cache").constrain(200); ObjectSet result = query.execute(); //ejecuta consulta mostrarConsulta(result);//muestra resultados de consulta }

//consulta SODA de ponentes con cache entre 50 y 200 public static void consultaSODAcacheEntre50_200(ObjectContainer db) { Query query = db.query(); query.constrain(ponente.class); //se declara una de las restricciones con Constraint Constraint constra1 = query.descend("cache").constrain(200).smaller(); //se enlazan las dos restricciones a aplicar query.descend("cache").constrain(50).greater().and(constra1 ); ObjectSet result = query.execute(); mostrarConsulta(result); }

//consultar los ponentes de cach 200 public static void consultarPonenteNQcache200(ObjectContainer db) { List res = db.query(new com.db4o.query.Predicate() { public boolean match(ponente p) { return p.getCache() == 200; } //mtodo abstracto @Override public boolean match(Object et) { throw new UnsupportedOperationException("Not supported yet."); } }); mostrarConsulta((ObjectSet) res); }

//consulta SODA de ponentes ordenados por cach, de ms a menos public static void consultaSODAponentesOrdenadosCache(ObjectContainer db) { Query query = db.query(); query.constrain(ponente.class); query.descend("cache").orderDescending(); ObjectSet result = query.execute(); mostrarConsulta(result); } MEtodo Main public static void main(String[] args) { System.out.println("PONENTES con cach 200: *****"); //Conexin, apertura o creacin de la base de objetos congreso.db4o consultarPonenteNQcache200(db); ObjectContainer db = System.out.println("CONSULTAS SODA: Db4oEmbedded.openFile(Db4oEmbedded.newConfiguration(), *****************************"); "congreso.db4o"); System.out.println("TODOS LOS PONENTES: *****"); //operaciones sobre la base de objetos congreso consultaSODAponentes(db); try { System.out.println("PONENTES con cach 200: *****"); almacenarPonentes(db); consultaSODAcache200(db); System.out.println("CONSULTAS QBE: System.out.println("PONENTES con cach entre 50 y 200: *****"); ******************************"); consultaSODAcacheEntre50_200(db); System.out.println("TODOS LOS PONENTES: *****"); System.out.println("TODOS los PONENTES de ms a menos consultarPonentes(db); cach: *****"); System.out.println("PONENTES con cach 200: *****"); consultaSODAponentesOrdenadosCache(db); consultarPonente200(db); } catch (Exception e) { System.out.println("PONENTE de nombre Antonio Camaco: //cdigo para el tratamiento de la excepcin *****"); } finally { db.close(); // cerrar la base de datos antes de salir consultarPonentePorNombre(db, "Antonio Camaco"); System.out.println("CONSULTAS NQ: } *******************************"); }

4.3.- Actualizacin de objetos simples.


Para modificar objetos almacenados debes seguir los siguientes pasos: Cambiar los valores del objeto con los nuevos valores. Almacenar de nuevo el objeto con el mtodo store() de la interfaz ObjectContainer. Db4o necesita conocer previamente un objeto para poder actualizarlo. Esto significa que para poder ser actualizados los objetos, stos deben de haber sido insertados o recuperados en la misma sesin; en otro caso se aadir otro objeto en vez de actualizarse. Para eliminar objetos almacenados utilizaremos el mtodo delete() de la interface ObjectContainer . //mtodo que modifica el e-mail de un ponente cuyo nif se pasa como parmetro // y almacena en la base de objetos los nuevos valores public static void actualizarEmailPonente(ObjectContainer db, String nif, String em) { //se consulta a la base de objetos por el ponente del nif indicado

ObjectSet res = db.queryByExample(new ponente(nif, null, null, 0)); ponente p = (ponente) res.next(); //se obtiene el objeto consultado en p p.setEmail(em); //se cambia el email del objeto db.store(p); //se alamcena de nuevo el objeto poenente } public static void borrarPonenteporNif(ObjectContainer db, String nif) { //se consulta a la base de objetos por el ponente del nif indicado ObjectSet res = db.queryByExample(new ponente(nif, null, null, 0)); ponente p = (ponente) res.next(); //se obtiene el objeto consultado en p db.delete(p); //se elimina el objeto poenente de la base de objetos } Y en el Main public static void main(String[] args) { ObjectContainer db = Db4oEmbedded.openFile(Db4oEmbedded.newConfiguration(), "congreso.db4o"); try { almacenarPonentes(db); consultarPonentes(db); consultarPonente200(db); actualizarEmailPonente(db, "22B", "isaperez@gmail.com"); borrarPonenteporNif(db, "11A"); consultarPonentes(db); } catch (Exception e) { //cdigo para el tratamiento de la excepcin } finally { db.close(); // cerrar la base de datos antes de salir } } 4.4.- Actualizacin de objetos estructurados. Los objetos estructurados son objetos que contienen a su vez a otros objetos (objetos hijo u objetos miembro). Los objetos estructurados se almacenan asignando valores con set() y despus persistiendo el objeto con store().La eliminacin o borrado de un objeto estructurado se realiza mediante el mtodo delete().Para eliminar objetos estructurados en cascada o de forma recursiva, eliminando los objetos miembro, habr que configurar de modo apropiado la base de objetos antes de abrirla, mediante el paquete com.db4o.config. En el caso de modo embebido, se har mediante la interface EmbeddedConfiguration. En la nueva configuracin se debe indicar cascadeOnDelete(true). Para actualizar de forma recursiva todos los objeto miembro habr que indicar en la configuracin cascadeOnUpdate(true). Clase estructurada Charla, formada por otra clase en segundo nivel, Ponente: package actualizarcongresoestructurados; this.pl = p; //clase que implementa un charla. Cada charla tiene un ttulo y est } asignada //Mtodo para obtener el ttulo de una charla public String getTitulo() { //a un ponente. CLASE ESTRUCTURADA: contiene un objeto return titulo; ponente public class charla { } private String titulo; //Mtodo para obtener la duracin de una charla private float duracion; public float getDuracion() { private ponente pl; return duracion; //constructor } public charla(String ti, float h) { //Mtodo para asignar el ponente de una charla this.titulo = ti; public void setDuracion(float h) { this.pl = null; this.duracion = h; this.duracion=h; } } //Mtodo para mostrar ttulo y ponente de una charla //Mtodo para obtener el ponente de una charla @Override public ponente getPonente() { public String toString() { return pl; return "Charla: " + titulo + ", " + duracion + " horas. } PONENTE: " +pl ; //Mtodo para asignar el ponente de una charla } } public void setPonente(ponente p) { Clase Principal para objetos estructurados, para consultas y actualizaciones System.out.println("ELIMINACIN de la charla XML:"); package actualizarcongresoestructurados; //API necesaria de db4o borrarCharlaporTitulo(db, "XML"); import com.db4o.Db4oEmbedded; System.out.println("CHARLAS Y PONENTES EXISTENTES tras import com.db4o.ObjectContainer; borrar charla XML:"); import com.db4o.ObjectSet; mostrarCharlasQBE(db); import com.db4o.query.Query; mostrarPonentes(db); public class Main { System.out.println("MODIFICACIN de las horas de la CHARLA public static void main(String[] args) { Db4o:"); //Conexin a la base de objetos y apertura de la base de objetos actualizarHorasCharla(db, "Db4o", 8.0f); congreso.db4o consultaSODACharla_concreta(db, "Db4o"); ObjectContainer db = } catch (Exception e) { Db4oEmbedded.openFile(Db4oEmbedded.newConfiguration(), //cdigo para el tratamiento de la excepcin "congreso.db4o"); } finally { //llamada a mtodos para operar con la base de objetos db.close(); // cerrar la base de datos antes de salir try { } } almacenarCharlas(db); System.out.println("CHARLAS EXISTENTES EN LA BDOO:"); //Almacenar objetos estructurados mostrarCharlasQBE(db); //Mtodo para insertar charlas en la Base de Objetos y almacenarlas System.out.println("CHARLAS EXISTENTES con ttulo XML:"); public static void almacenarCharlas(ObjectContainer db) { consultaSODACharla_concreta(db, "XML"); //se crean 4 objetos tipo charla System.out.println("CHARLAS EXISTENTES del ponente charla c1 = new charla("Bases de Datos Orientadas a Objetos", 2); ANTONIO CAMACO:"); charla c2 = new charla("MySQL y PostGreSQL", 3); mostrarCharlasCamacoQBE(db);

charla c3 = new charla("XML", 2); charla c4 = new charla("Db4o", 3); //se crean 4 objetos ponente ponente p1 = new ponente("11A", "Antonio Camaco", "acamacho@gmail.es", 300); ponente p2 = new ponente("22B", "Isabel Prez", "iperez@hotmail.es", 100); ponente p3 = new ponente("33C", "Ana Navarro", "anavarro@yahoo.com", 200); //se le asigna un ponente a cada charla c1.setPonente(p1); c2.setPonente(p2); c3.setPonente(p3); c4.setPonente(p1); //Persistir Objetos: almacenamos los objetos con el mtodo store() db.store(c1); db.store(c2); db.store(c3); db.store(c4);

//Consulta de objetos estructurados. Consulta QBE //Consulta de las charlas del ponenete Anotnio Camaco public static void mostrarCharlasCamacoQBE(ObjectContainer db) { //se crea objeto ponente con patrn de bsqueda (el ejemplo) ponente p = new ponente(null, "Antonio Camaco", null, 0); //se crea el objeto charla con patrn de bsqueda charla c = new charla(null, 0); c.setPonente(p); //se asocia el ponente de bsqueda a la charla ObjectSet resul = db.queryByExample(c); //Consulta las charlas con patrones indicados mostrarConsulta(resul);//mtodo que muestra los objetos recuperados de BDOO } //Borrado de objetos estructurados. Se utiliza Consulta SODA //Se elimina la charla de ttulo tit sin eliminar al ponente asociado

public static void borrarCharlaporTitulo(ObjectContainer db, String tit) { Query query = db.query(); //declaracin de un objeto query(). query.constrain(charla.class);//establece la clase a la que se aplicar la restriccin } query.descend("titulo").constrain(tit);//establece la restriccin de bsqueda ObjectSet resul = query.execute();//ejecuta consulta con //Mtodo para mostrar objetos recuperados de la Base de Objetos public static void mostrarConsulta(ObjectSet resul) { restriccin bsqueda while (resul.hasNext()) { //bucle que recupera los objetos charla y //mensaje indicando el total de objetos recuperados elimina de la BDOO System.out.println("Recuperados " + resul.size() + " Objetos"); charla c = (charla) resul.next(); while (resul.hasNext()) {//bucle que obtiene objeto a objeto System.out.println("Eliminando: " + c); System.out.println(resul.next()); db.delete(c); } } } //Consulta QBE de objetos estructurados. Consulta de todas las charlas. } //Consulta de todos los objetos ponente. Consulta QBE public static void mostrarCharlasQBE(ObjectContainer db) { //se crea el objeto charla patrn de bsqueda public static void mostrarPonentes(ObjectContainer db) { charla c = new charla(null, 0); //se crea objeto p con patrn de bsqueda (el ejemplo) //Consulta las charlas con patrones indicados ponente p = new ponente(null, null, null, 0); ObjectSet resul = db.queryByExample(c); //consulta los ponentes de patrn ponente(null, null, null, 0). Consulta mostrarConsulta(resul);//mtodo que muestra los objetos QBE ObjectSet res = db.queryByExample(p); recuperados de BDOO mostrarConsulta(res); //mtodo que muestra los objetos } recuperados de BDOO //Consulta SODA de objetos estructurados } //Se consulta la charla cuyo ttulo se pasa en parmetro tit //Modificacin de Objetos estructurados. Con consulta QBE public static void consultaSODACharla_concreta(ObjectContainer //Actualiza la duracin de la charla de ttulo tit en d horas db, String tit) { public static void actualizarHorasCharla(ObjectContainer db, String Query query = db.query(); //declara un objeto query tit, float d) { query.constrain(charla.class);//establece la clase a la que se //consulta la charla de patrn charla(tit,0). Consulta QBE aplicar la restriccin ObjectSet res = db.queryByExample(new charla(tit, 0)); query.descend("titulo").constrain(tit);//establece la restriccin de charla c = (charla) res.next(); //obtiene la charla consultada bsqueda c.setDuracion(d); //asigna la nueva duracin ObjectSet resul = query.execute();//ejecuta consulta db.store(c); //almacena la charla modificada mostrarConsulta(resul);//mtodo que muestra los objetos } recuperados de la BDOO } } Clase Principal para objetos estructurados, para eliminacin de objetos package eliminacioncascada; //API necesaria de db4o //llamada a mtodos para operar con la base de objetos import com.db4o.Db4oEmbedded; try { import com.db4o.ObjectContainer; almacenarCharlas(db); import com.db4o.ObjectSet; System.out.println("CHARLAS EXISTENTES EN LA import com.db4o.config.EmbeddedConfiguration; //establecer BDOO:"); configuracin de conexin mostrarCharlasQBE(db); import com.db4o.query.Query; System.out.println("ELIMINACIN de la charla XML:"); public class Main { borrarCharlaporTitulo(db, "XML"); public static void main(String[] args) { System.out.println("CHARLAS Y PONENTES EXISTENTES //Conexin a la base de objetos y apertura de la base de objetos tras borrar charla XML:"); congreso.db4o mostrarCharlasQBE(db); //Se CONFIGURA la apertura de manera que al eliminar un objeto mostrarPonentes(db); estructurado } catch (Exception e) { //de tipo charla, se eliminen tambin los objeto hilo tipo ponente. //cdigo para el tratamiento de la excepcin //Se indica la nueva configuracin de conexin, con borrado en } finally { cascada db.close(); // cerrar la base de datos antes de salir EmbeddedConfiguration config = } Db4oEmbedded.newConfiguration(); } //Almacenar objetos estructurados config.common().objectClass(charla.class).cascadeOnDelete(tr //Mtodo para insertar charlas en la Base de Objetos y ue); //Se abre la conexin a la base de objetos congreso.db4o almacenarlas ObjectContainer db = Db4oEmbedded.openFile(config, public static void almacenarCharlas(ObjectContainer db) { "congreso.db4o"); //se crean 4 objetos tipo charla

charla c1 = new charla("Bases de Datos Orientadas a Objetos", 2); charla c2 = new charla("MySQL y PostGreSQL", 3); charla c3 = new charla("XML", 2); charla c4 = new charla("Db4o", 3); //se crean 4 objetos ponente ponente p1 = new ponente("11A", "Antonio Camaco", "acamacho@gmail.es", 300); ponente p2 = new ponente("22B", "Isabel Prez", "iperez@hotmail.es", 100); ponente p3 = new ponente("33C", "Ana Navarro", "anavarro@yahoo.com", 200); //se le asigna un ponente a cada charla c1.setPonente(p1); c2.setPonente(p2); c3.setPonente(p3); c4.setPonente(p1); //Persistir Objetos: almacenamos los objetos con el mtodo store() db.store(c1); db.store(c2); db.store(c3); db.store(c4); } //Mtodo para mostrar objetos recuperados de la Base de Objetos public static void mostrarConsulta(ObjectSet resul) { //mensaje indicando el total de objetos recuperados System.out.println("Recuperados " + resul.size() + " Objetos"); while (resul.hasNext()) {//bucle que obtiene objeto a objeto System.out.println(resul.next()); } } //Consulta QBE de objetos estructurados. Consulta de todas las charlas. public static void mostrarCharlasQBE(ObjectContainer db) { //se crea el objeto charla patrn de bsqueda

charla c = new charla(null, 0); //Consulta las charlas con patrones indicados ObjectSet resul = db.queryByExample(c); mostrarConsulta(resul);//mtodo que muestra los objetos recuperados de BDOO } //Borrado de objetos estructurados. Se utiliza Consulta SODA //Se elimina la charla de ttulo tit sin eliminar al ponente asociado public static void borrarCharlaporTitulo(ObjectContainer db, String tit) { Query query = db.query(); //declaracin de un objeto query(). query.constrain(charla.class);//establece la clase a la que se aplicar la restriccin query.descend("titulo").constrain(tit);//establece la restriccin de bsqueda ObjectSet resul = query.execute();//ejecuta consulta con restriccin bsqueda while (resul.hasNext()) { //bucle que recupera los objetos charla y elimina de la BDOO charla c = (charla) resul.next(); System.out.println("Eliminando: " + c); db.delete(c); } } //Consulta de todos los objetos ponente. Consulta QBE public static void mostrarPonentes(ObjectContainer db) { //se crea objeto p con patrn de bsqueda (el ejemplo) ponente p = new ponente(null, null, null, 0); //consulta los ponentes de patrn ponente(null, null, null, 0). Consulta QBE ObjectSet res = db.queryByExample(p); mostrarConsulta(res); //mtodo que muestra los objetos recuperados de BDOO } }

5.- El lenguaje de consulta de objetos OQL. OQL (Object Query Languaje) es el lenguaje de consulta de objetos propuesto en el estndar ODMG. Las siguientes son algunas de las caractersticas ms relevantes de OQL: Es un lenguaje declarativo del tipo de SQL Su sintaxis es similar a la de SQL No posee primitivas para modificar el estado de los objetos Puede ser usado como un lenguaje autnomo o incrustado dentro de otros lenguajes Una consulta OQL incrustada en uno de estos lenguajes de programacin puede devolver objetos que coincidan con el sistema de tipos de ese lenguaje. Permite acceso tanto asociativo como navegacional: o Una consulta asociativa devuelve una coleccin de objetos. o Una consulta navegacional accede a objetos individuales y las interrelaciones entre objetos sirven para navegar entre objetos. 5.1.- Sintaxis, expresiones y operadores.
sentencia SELECT del OQL estndar es la siguiente:

SELECT [DISTINCT] <expresin, ...> FROM <lista from> [WHERE <condicin> ] [ORDER BY <expresin>] SELECT p.nombre, p.email FROM p in Profesor WHERE p.ingreso <= 1990 ORDER BY p.nombre;

En las consultas se necesita un punto de entrada, que suele ser el nombre de una clase. El resultado de una consulta es una coleccin que puede ser tipo bag (si hay valores repetidos) o tipo set (no hay valores repetidos). En este ltimo caso habr que especificar SELECT DISTINCT. En general, una consulta OQL puede devolver un resultado con una estructura compleja especificada en la misma consulta utilizando struct. Adems, en una consulta OQL se pueden utilizar, entre otros, los siguientes operadores y expresiones: Operadores de acceso: "." / "->" aplicados a un atributo, una expresin o una relacin. FIRST / LAST (primero / ltimo elemento de una lista o un vector). Operadores aritmticos: +, -, *, /, -(unario), MOD, ABS para formar expresiones aritmticas. Operadores relacionales: >, <, >=, <=, <>, = que permiten comparaciones y construir expresiones lgicas. Operadores lgicos: NOT, AND, OR que permiten enlazar otras expresiones. Operadores de colecciones como funciones de agregacins (MAX(), MIN(), COUNT(), SUM() y AVG()) y cuantificadores (FOR ALL, EXISTS). Realizacin de agrupaciones mediante GROUP BY y filtro de los grupos mediante HAVING. Combinacin de consultas mediante JOINs Unin, interseccin y resta de colecciones mediante los operadores UNION, INTERSEC y EXCEPT.

5.2.- Matisse, un gestor de objetos que incorpora OQL. El propio gestor proporciona el driver matisse.jar para interactuar
con aplicaciones escritas en Java. Dentro de los paquetes del API destacamos: com.matisse. Proporciona las clases e interfaces bsicos para trabajar con Java y una base de datos de objetos Matisse. MtDatabase. Clase que proporciona todos los mtodos para realizar las conexiones y transacciones en la base de objetos. com.matisse.sql. Proporciona clases que permiten interactuar con la base de objetos va JDBC. Descargar en www.matisse.com , el archivo matisse.jar se encuentra en la carpeta lib de instalacion, agregar en netbeans en biblioteca del proyecto. Creacion de base de datos doctorado:

Metodo Main: package doctoradomatisse; //librera proporcionada por Matisse (necesaria porque vamos a utilizar los //objetos propios de Matisse, en lugar de los genricos que nos //proporcionara una conexin mediante JDBC) import com.matisse.MtDatabase; import com.matisse.MtException; public class Main { public static void main(String[] args) { //crea el objeto base de datos MtDatabase indicando la cadena de conexin //nombre del host "zailla" y base de datos "doctorado" //no se necesita usuario porque no se ha deficnido un control de acceso MtDatabase db = new MtDatabase("zailla", "doctorado"); //mensaje para la Salida System.out.println("=========== connectFromMtDatabase ==========\n"); try { //conecta con la base de datos db.open(); //inicia una transaccin (matisse gestiona todas las operaciones como transacciones) db.startTransaction(); //insertar datos en registros insertarObjetos(db); } catch (MtException mte) { //mensaje para la Salida System.out.println("MtException : " + mte.getMessage()); } finally { //confirma cualquier transaccin en proceso if (db.isTransactionInProgress()) { db.commit(); } //cierra la base de datos db.close(); } } private static void insertarObjetos(MtDatabase db) { //crea objetos Departamento Departamento d1 = new Departamento(db);

d1.setNombre("Bases de Datos"); Departamento d2 = new Departamento(db); d2.setNombre("Lenguajes"); // Crea objetos Tesis Tesis t1 = new Tesis(db); t1.setTitulo("Persistencia de objetos"); t1.setTema("Bases de Objetos"); Tesis t2 = new Tesis(db); t2.setTitulo("Bases de Datos Nativas XML"); t2.setTema("Bases de Datos XML"); Tesis t3 = new Tesis(db); t3.setTitulo("Mapeo Objeto-Relacional"); t3.setTema("Bases de Datos"); Tesis t4 = new Tesis(db); t4.setTitulo("Multiproceso en Java"); t4.setTema("Lenguajes de Programacin"); // Crea un objeto Profesor Profesor p1 = new Profesor(db); p1.setNombre("Ana Martos Gil"); p1.setEmail("ana.martos@universi.es"); p1.setIngreso(1990); Profesor p2 = new Profesor(db); p2.setNombre("Isabel Ruz Granados"); p2.setEmail("isabel.ruz@universi.es"); p2.setIngreso(1986); Profesor p3 = new Profesor(db); p3.setNombre("Antonio Barea Navarro"); p3.setEmail("antonioa.barea@universi.es"); p3.setIngreso(1995); //establece relaciones entre Profesor y Departamentoanteriormente creados //Al establecer una relacin no hace falta establecer la inversa*/ p1.setPertenece(d1); p1.appendDirige(t1); p2.setPertenece(d1); p2.appendDirige(t2); p2.appendDirige(t3); p3.setPertenece(d2); p3.appendDirige(t4); } }

5.3.- Ejecucin de Sentencias OQL.


Por ejemplo, para recuperar el valor de todos los atributos de los objetos tipo Profesor, escribiramos la siguiente sentencia OQL: SELECT * FROM Profesor; Y para recuperar del atributo nombre de los objetos tipo Profesor cuyo ao de ingreso es anterior al 1990, escribiramos la siguiente sentencia : SELECT nombre FROM Profesor WHERE ingreso <= 1990; Toda sentencia SELECT finaliza en punto y coma. Se puede usar where, Group by, Al recupear todos los atributos de una clase mediante SELECT *, la consulta retornar el OID de cada objeto recuperado, as como las interrelaciones o relaciones definidas para esa clase. El OID y la interrelacin son del tipo string y se representan mediante un nmero hexadecimal. se pueden hacer JOIN de clases Ejemplo: nombre de cada profesor y ttulo y tema de las tesis que dirige con JOIN SELECT p.nombre, t.titulo, t.tema FROM Profesor p JOIN Tesis t ON t.es_dirigida = p.OI Mediante SELECT se pueden realizar consultas navegacionales haciendo referencia a las interrelacionaes entre objetos. Ejemplo: nombre de cada profesor y ttulo y tema de las tesis que dirige, navegacional SELECT t.titulo AS "Tesis", tema, t.es_dirigida.nombre AS "Profesor " FROM Tesis t; Tambin se pueden realizar consultas navegacionales a travs de la referencia de los objetos (REF()). Ejemplo: tesis que dirigen los profesores con ingreo el 1990 o posterior SELECT REF(p.dirige) FROM Profesor p 1) WHERE p.ingreo >= 1990;

5.4.- Ejecucin de sentencias OQL va JDBC.


Para ello, la conexin a la base de objetos se realizar va JDBC. Matisse proporciona dos formas de manipular objetos va JDBC: mediante JDB puro o mediante una mezcla de JDBC y Matisse. Para crear una conexin va JDBC puro utilizaremos java.SQL.* y com.Matisse.SQL.MtDriver, no siendo necesario en este caso el paquete com.Matisse. La cadena de conexin ser de la forma: String url = "JDBC:mt://" + hostname + "/" + dbname; La conexin se realizar mediante Connection jcon = DriverManager.getConnection(url); Para crear una conexin va JDBC y Matisse (a travs de MtDatabase) se necesita java.SQL.* y com.Matisse.MtDatabase. La cadena de conexin ser de la forma: MtDatabase db = new MtDatabase(hostname, dbname); La conexin se realizar mediante: db.open(); y Connection jcon = db.getJDBCConnection(); package doctoradomatisseoql; rsMetaData.getColumnName(i + 1)) + " "); //bibliotecas necesarias } import com.matisse.*; System.out.println(""); import com.matisse.sql.MtResultSet; for (int i = 0; i < numberOfColumns; ++i) { import java.sql.*; System.out.print(" ----------------------------- "); public class Main { } public static void main(String[] args) { System.out.println(""); String nombrep, emailp; //Crea un objeto MtDatabase asociando la cadena de conexin // Read filas (objetos) one by one MtDatabase dbcon = new MtDatabase("localhost", while (rset.next()) { "doctorado"); // Obtiene los valores de la primera y segunda columna // Abrir una conexin a la base de objetos nombrep = rset.getString(1); emailp = rset.getString(2); dbcon.open(); try { Connection jdbcon = dbcon.getJDBCConnection(); // Crea la sentencia // Imprime la fila en curso Statement stmt = jdbcon.createStatement(); System.out.println(String.format("%30s", nombrep) + " " //Define la consulta SELECT + String.format("%30s", emailp)); String query = "SELECT nombre, email FROM Profesor;"; } //Ejecuta la consulta y obtiene un EesulSet // resetea y cierra la conexin a la base de objetos ResultSet rset = stmt.executeQuery(query); rset.close(); stmt.close(); // Imprime total de objetos recuperados } catch (SQLException e) { System.out.println("Total selected: " System.out.println("SQLException: " + e.getMessage()); } + ((MtResultSet) rset).getTotalNumObjects()); if (dbcon.isVersionAccessInProgress()) { System.out.println(""); // Imprime los nombre de columna dbcon.endVersionAccess(); } else if (dbcon.isTransactionInProgress()) { ResultSetMetaData rsMetaData = rset.getMetaData(); int numberOfColumns = rsMetaData.getColumnCount(); dbcon.rollback(); // Obtiene los nombres de columna; indexa las columnas comenzando } desde 1 dbcon.close(); for (int i = 0; i < numberOfColumns; i++) { } System.out.print(String.format("%30s", }

6.- Caractersticas de las bases de datos objeto-relacionales.


Como consecuencia de esto, aparecen nuevas caractersticas, entre las que podemos destacar las siguientes: Tipos definidos por el usuario. Tipos Objeto. Posibilidad de creacin de objetos como nuevo tipo de dato que permiten relaciones anidadas. Reusabilidad. Posibilidad de guardar esos tipos en el gestor de la BDOR, para reutilizarlos en tantas tablas como sea necesario Creacin de funciones. Posibilidad de definir funciones y almacenarlas en el gestor. Tablas anidadas. Se pueden definir columnas como arrays o vectores multidimensionales, Herencia con subtipos y subtablas.

6.1.- El estndar SQL99.


Por ejemplo, el siguiente segmento de SQL crea un nuevo tipo de dato, un tipo estructurado de nombre profesor y que incluye en su definicin un mtodo, el mtodo sueldo() . CREATE TYPE profesor AS ( id INTEGER, nombre VARCHAR (20), sueldo_base DECIMAL (9,2), complementos DECIMAL (9,2), INSTANTIABLE NOT FINAL METHOD sueldo() RETURNS DECIMAL (9,2)); CREATE METHOD sueldo() FOR profesor BEGIN ...... END;

7.- Gestores de Bases de Datos Objeto-Relacionales. A continuacin te indicamos algunos ejemplos de gestores objetorelacionales, tanto de cdigo libre como propietario, todos ellos con soporte para Java: De cdigo abierto: PostgreSQL Apache Derby De cdigo propietario Oracle First SQL DB2 de IBM 7.1.- Instalacin del Gestor PostgreSQL.

Para los ejemplos, crearemos una base de datos de prueba denominada anaconda. Con la ayuda de pgAdmin, esta tarea puede realizarse en uno cuantos clics:

7.2.- Tipos de datos: tipos bsicos y tipos estructurados. PostgreSQL no soporta herencia de tipos pero permite definir
nuevos tipos de datos mediante los mecanismos de extensin. Te vamos a comentar tres categoras de tipos de datos que encontramos en PostgreSQL: Tipos bsicos: el equivalente a los tipos de columna usados en cualquier base de datos relacional. Tipos compuestos: un conjunto de valores definidos por el usuario con estructura de fila de tabla, y que como tal puede estar formada por tipos de datos distintos. Tipos array: un conjunto de valores distribuidos en un vector multidimensional, con la condicin de que todos sean del mismo tipo de dato (bsico o compuesto). Ofrece ms funcionalidades que el array del estndar SQL99. Entre los tipos bsicos, podemos destacar: Tipos numricos. Aparte de valores enteros, nmeros de coma flotantes, y nmeros de precisin arbitraria, PostgreSQL incorpora tambin un tipo entero auto-incremental denominado serial. Tipos de fecha y hora. Adems de los tpicos valores de fecha, hora e instante, PostgreSQL incorpora el tipo interval para representar intervalos de tiempo. Tipos de cadena de caracteres. Prcticamente los mismos que en cualquier BDR. Tipos largos. Como por ejemplo, el tipo BLOB para representar objetos binarios. En la actualidad presentes en muchas BDR como MySQL. Los tipos compuestos de PostgreSQL son el equivalente a los tipos estructurados definidos por el usuario del estndar SQL99. De hecho, son la base sobre la que se asienta el soporte a objetos. Por ejemplo, podemos crear un nuevo tipo, el tipo direccin a partir del nombre de la calle (varchar), del nmero de la calle (integer) y del cdigo postal (integer), de la siguiente forma: CREATE TYPE direccion AS ( calle varchar, numero integer, codigo_postal integer); y luego definir la tabla de nombre afiliados, con una columna basada en el nuevo tipo: CREATE TABLE afiliados AS( afiliado_id serial, nombre varchar(45), apellidos varchar(45), domicilio direccion);

7.3.- Conexin mediante JDBC.

Una vez integrado en un proyecto, el driver puede utilizarse desde cualquiera de sus clases mediante un: import java.sql.* Recuerda que en JDBC, una base de datos est representada por una URL. La cadena correspondiente tiene una de las tres formas siguientes: jdbc: postgresql: base de datos jdbc: postgresql: //host/base de datos jdbc: postgresql: //host: puerto/base de datos Para conectar con la base de datos, utilizaremos el mtodo DriverManager.getConnection() que devuelve un objeto Connection (la conexin con la base de datos). Una de las posibles sintaxis de este mtodo es: Connection conn = DriverManager.getConnection(url, username, password); Una vez abierta, la conexin se mantendr operativa hasta que se llame a su mtodo close() para efectuar la desconexin. Si al intentar conectar con la base de datos sta no existe, se generar una excepcin del tipo PSQLException "FATAL: no existe la base de datos ...". En cualquier caso se requiere un bloque try-catch .

//cadena url de la base de datos anaconda en el servidor local (no hay //que indicar el puerto si es el por defecto) String url = "jdbc:postgresql://localhost/anaconda"; //conexin con la base de datos Connection conn = null; try { //abre la conexin con la base de datos a la que apunta el url //mediante la contrasea del usuario postgres conn = DriverManager.getConnection(url, "postgres", "password"); //hace algo til... } catch (SQLException ex) { //imprime la excepcin System.out.println(ex.toString()); } finally { //cierra la conexin conn.close(); } 7.4.- Consulta y actualizacin de tipos bsicos. PostgreSQL implementa los objetos como filas, las clases como tablas, y los atributos como columnas. Por tanto, si nuestra conexin es conn, para enviar un comando Statement haramos lo siguiente: Crear la sentencia, por ejemplo.: Statement sta = conn.createStatement(); Ejecutar la sentencia: sta.executeQuery(string sentenciaSQL); si sentenciaSQL es una consulta (SELECT) sta.executeUpdate(string sentenciaSQL); si sentenciaSQL es una actualizacin (INSERT, UPDATE O DELETE) sta.execute(string sentenciaSQL); si sentenciaSQL es un CREATE, DROP, o un ALTER

Ejemplo
package PaquetePrincipal; * el tipo de las claves primarias "mes_id" y "provincia_id" es entero. El * tipo de la clave primaria de la tabla 'datos_meteo' es serial (entero /****************************************************************************** * ilustra caracterstica meramente relacionales de PostgreSQL mediante * autoincremental en PostgreSQL). El resto son cadenas de longitud variable el * , o numeric (el tipo numrico para clculos exactos). * uso de comandos public class Main { * * la tabla 'meses' tiene un relacion de uno a varios con la tabla public static void main(String[] args) throws SQLException { * 'datos_meteo', mediante el campo 'mes_id' de la segunda //cadena url de la base de datos anaconda en el servidor local * String url = "jdbc:postgresql://localhost/anaconda"; * la tabla 'provincias' tiene un relacion de uno a varios con la tabla //conexin con la base de datos * 'datos_meteo', mediante el campo 'provincia_id' de la segunda Connection conn = null; * try { * ambas relaciones implementan actualizaciones y eliminaciones en //abre la conexin con la base de datos a la que apunta el url cascada //mediante la contrasea del usuario postgres conn = DriverManager.getConnection(url, "postgres", "1234"); private static void crearTablas(Connection conn) throws //elimina las tablas (si existen) SQLException { drop_Ejemplo(conn); //consulta //vuelve a crear las tablas de ejemplo String consulta = "CREATE TABLE meses(" crearTablas(conn); + "mes_id integer NOT NULL," //inserta algunos regitros + "mes varchar(25)," insertarRegistros(conn); + "CONSTRAINT mes_id PRIMARY KEY (mes_id )" + ");" //realiza alguna consultas consulta_Ejemplo1(conn); consulta_Ejemplo2(conn); + "CREATE TABLE provincias(" //modifica algunos registros + "provincia_id integer NOT NULL," update_Ejemplo(conn); + "provincia varchar(25)," //borra algunos registros + "CONSTRAINT provincia_id PRIMARY KEY (provincia_id )" delete_Ejemplo(conn); + ");" } catch (SQLException ex) { //imprime la excepcin + "CREATE TABLE datos_meteo(" System.out.println(ex.toString()); + "datos_meteo_id serial NOT NULL," } finally { + "provincia_id integer," //cierra la conexin + "mes_id integer," conn.close(); + "temp_min numeric," } + "temp_max numeric," } + "precipitaciones integer," /**************************************************************************** + "CONSTRAINT datos_meteo_id PRIMARY KEY * borra todas las tablas del ejemplo (si es que existen) (datos_meteo_id )," private static void drop_Ejemplo(Connection conn) throws + "CONSTRAINT mes_id FOREIGN KEY (mes_id) SQLException { REFERENCES " //consulta SQL + "meses (mes_id) MATCH SIMPLE ON UPDATE CASCADE String consulta = "DROP TABLE IF EXISTS datos_meteo;" ON " + "DROP TABLE IF EXISTS meses;" + "DELETE CASCADE," + "DROP TABLE IF EXISTS provincias;"; + "CONSTRAINT provincia_id FOREIGN KEY (provincia_id) //comando auxiliar para ejecutar la consulta REFERENCES " Statement sta = conn.createStatement(); + "provincias (provincia_id) MATCH SIMPLE ON UPDATE //ejecuta la consulta CASCADE " sta.execute(consulta); + "ON DELETE CASCADE" //cierra el objeto auxiliar + ");"; sta.close(); //comando auxiliar para ejecutar la consulta } Statement sta = conn.createStatement(); * creamos las tablas ('meses', 'provincias' y 'datos_meteo') y //ejecuta la consulta establecemos sta.execute(consulta); * tanto las claves primarias ('mes_id', 'provincia_id' y 'datos_meteo_id'), //cierra el objeto auxiliar * como las forneas (columnas 'mes_id' y 'provincia_id' de la tabla sta.close(); * 'datos_meteo') } *

+ "temp_max, precipitaciones) VALUES (4, 10, 13.3, 23.4, * insertamos algunos registros en las tablas (por suspuesto, respetando 74);"; //comando auxiliar para ejecutar la consulta * la integridad de las relaciones) Statement sta = conn.createStatement(); private static void insertarRegistros(Connection conn) throws SQLException { //ejecuta la consulta //consulta sta.execute(consulta); String consulta = "INSERT INTO meses (mes_id, mes) VALUES (1, //cierra el objeto auxiliar 'enero');" sta.close(); + "INSERT INTO meses (mes_id, mes) VALUES (2, 'febrero');" } + "INSERT INTO meses (mes_id, mes) VALUES (3, 'marzo');" * mostramos todos los registros de la tabla 'datos_meteo'. Tanto en + "INSERT INTO meses (mes_id, mes) VALUES (4, 'abril');" + "INSERT INTO meses (mes_id, mes) VALUES (5, 'mayo');" bruto, * como mostrando los nombres de los meses y de la provincias. En el + "INSERT INTO meses (mes_id, mes) VALUES (6, 'junio');" + "INSERT INTO meses (mes_id, mes) VALUES (7, 'julio');" segundo + "INSERT INTO meses (mes_id, mes) VALUES (8, 'agosto');" * caso, redondeamos las columnas 'temp_min' y 'temp_max" + "INSERT INTO meses (mes_id, mes) VALUES (9, private static void consulta_Ejemplo1(Connection conn) throws 'septiembre');" SQLException { // + "INSERT INTO meses (mes_id, mes) VALUES (10, 'octubre');" System.out.print("Todos los datos meteorolgicos, tanto en + "INSERT INTO meses (mes_id, mes) VALUES (11, bruto:\n"); //consulta SQL 'noviembre');" String consulta = "SELECT * FROM datos_meteo"; + "INSERT INTO meses (mes_id, mes) VALUES (12, //comando auxiliar para ejecutar la consulta 'diciembre');" Statement sta = conn.createStatement(); //ejecuta la consulta para que devuelva un conjunto de registros + "INSERT INTO provincias (provincia_id, provincia) " ResultSet res = sta.executeQuery(consulta); + "VALUES (1, 'Barcelona');" //imprime el resultado + "INSERT INTO provincias (provincia_id, provincia) " imprimir_ResultSet(res); + "VALUES (2, 'Madrid');" // + "INSERT INTO provincias (provincia_id, provincia) " System.out.print("\ncomo con los valores tomados de las " + "VALUES (3, 'Murcia');" + "tablas relacionadas:\n"); + "INSERT INTO provincias (provincia_id, provincia) " //consulta SQL + "VALUES (4, 'Valencia');" consulta = "SELECT " + "datos_meteo.datos_meteo_id, " + "INSERT INTO datos_meteo (provincia_id, mes_id, + "provincias.provincia, " temp_min, " + "meses.mes, " + "temp_max, precipitaciones) VALUES (1, 1, 4.4, 13.4, 41);" + "round(datos_meteo.temp_min), " + "INSERT INTO datos_meteo (provincia_id, mes_id, + "round(datos_meteo.temp_max), " temp_min, " + "datos_meteo.precipitaciones " + "temp_max, precipitaciones) VALUES (1, 4, 8.5, 17.6, 49);" + "FROM meses,provincias,datos_meteo " + "INSERT INTO datos_meteo (provincia_id, mes_id, + "WHERE " temp_min, " + "meses.mes_id=datos_meteo.mes_id " + "temp_max, precipitaciones) VALUES (1, 7, 18.6, 27.5, 20);" + "AND " + "INSERT INTO datos_meteo (provincia_id, mes_id, + "provincias.provincia_id=datos_meteo.provincia_id"; temp_min, " //comando auxiliar para ejecutar la consulta + "temp_max, precipitaciones) VALUES (1, 10, 12.6, 21.5, sta = conn.createStatement(); 91);" //reutiliza el comando para enviar la nueva consulta y que + "INSERT INTO datos_meteo (provincia_id, mes_id, //devuelva un ResultSet temp_min, " res = sta.executeQuery(consulta); + "temp_max, precipitaciones) VALUES (2, 1, 0.3, 10.6, 33);" + "INSERT INTO datos_meteo (provincia_id, mes_id, //imprime el resultado temp_min, " imprimir_ResultSet(res); + "temp_max, precipitaciones) VALUES (2, 4, 5.4, 18.0, 39);" //cierra los objetos auxiliares + "INSERT INTO datos_meteo (provincia_id, mes_id, res.close(); temp_min, " sta.close(); + "temp_max, precipitaciones) VALUES (2, 7, 16.1, 33.0, 11);" } + "INSERT INTO datos_meteo (provincia_id, mes_id, temp_min, " + "temp_max, precipitaciones) VALUES (2, 10, 8.3, 20.6, 39);" * calcula la temperatura media por mes de Murcia (provincia_id=3) private static void consulta_Ejemplo2(Connection conn) throws + "INSERT INTO datos_meteo (provincia_id, mes_id, SQLException { temp_min, " System.out.print("\nTemperatura media por mes de Murcia:\n"); + "temp_max, precipitaciones) VALUES (3, 1, 5.12, 15.82, //consulta SQL 38);" String consulta = "SELECT " + "INSERT INTO datos_meteo (provincia_id, mes_id, + "meses.mes, " temp_min, " + + "temp_max, precipitaciones) VALUES (3, 4, 9.3, 19.9, 25);" "ROUND((datos_meteo.temp_max+datos_meteo.temp_min)/2,2) " + "INSERT INTO datos_meteo (provincia_id, mes_id, + "FROM meses,datos_meteo " temp_min, " + "WHERE " + "temp_max, precipitaciones) VALUES (3, 7, 19.9, 28.4, 6);" + "meses.mes_id=datos_meteo.mes_id " + "INSERT INTO datos_meteo (provincia_id, mes_id, + "AND " temp_min, " + "datos_meteo.provincia_id=3"; + "temp_max, precipitaciones) VALUES (3, 10, 18.7, 23.4, //comando SQL 14);" Statement sta = conn.createStatement(); + "INSERT INTO datos_meteo (provincia_id, mes_id, //ejecuta la consulta para que devuelva un conjunto de registros temp_min, " ResultSet res = sta.executeQuery(consulta); + "temp_max, precipitaciones) VALUES (4, 1, 5.0, 15.5, 38);" //imprime el resultado + "INSERT INTO datos_meteo (provincia_id, mes_id, imprimir_ResultSet(res); temp_min, " //cierra los objetos auxiliares + "temp_max, precipitaciones) VALUES (4, 4, 9.4, 20.6, 38);" res.close(); + "INSERT INTO datos_meteo (provincia_id, mes_id, sta.close(); temp_min, " + "temp_max, precipitaciones) VALUES (4, 7, 19.8, 30.9, 14);" } + "INSERT INTO datos_meteo (provincia_id, mes_id, temp_min, "

* cambia la clave principal del registro 'Valencia' en la tabla 'provincias' * (de 4 a 5), y comprueba la actualizacin en cascada de los registros * relacionados en la tabla 'datos_meteo' private static void update_Ejemplo(Connection conn) throws SQLException { System.out.print("\nCambia la clave principal de 'Valencia' en la tabla " + "'provincias'(de 4 a 5)."); //consulta SQL String consulta = "UPDATE provincias " + "SET provincia_id=5 " + "WHERE " + "provincia_id=4"; //comando SQL Statement sta = conn.createStatement(); //ejecuta la consulta para que muestre el nmero de filas modificadas System.out.print("\nComo resultado, " + sta.executeUpdate(consulta) + " fila actualizada:\n"); //nueva consulta SQL consulta = "SELECT * FROM provincias"; //reutiliza el comando para enviar la nueva consulta y que //devuelva un ResultSet ResultSet res = sta.executeQuery(consulta); //imprime el resultado imprimir_ResultSet(res); System.out.print("\ny muestra la actualizacin en cascada de los registros " + "relacionados en la tabla 'datos_meteo':\n"); //nueva consulta SQL consulta = "SELECT * FROM datos_meteo WHERE provincia_id=5"; //reutiliza el comando para enviar la nueva consulta y que //devuelva un ResultSet res = sta.executeQuery(consulta); //imprime el resultado imprimir_ResultSet(res); //cierra los objetos auxiliares res.close(); sta.close(); } * borra la provincia de 'Valencia' en la tabla 'provincias', y comprueba el * borrado en cascada de los registros relacionados en la tabla 'datos_meteo' }

+ " fila eliminada:\n"); //nueva consulta consulta = "SELECT * FROM provincias"; //reutiliza el comando para enviar la nueva consulta y que //devuelva un ResultSet ResultSet res = sta.executeQuery(consulta); //imprime el resultado imprimir_ResultSet(res);

System.out.print("\ny muestra el borrado en cascada de los registros " + "relacionados en la tabla 'datos_meteo':\n"); //nueva consulta consulta = "SELECT " + "datos_meteo.datos_meteo_id, " + "provincias.provincia, " + "meses.mes, " + "round(datos_meteo.temp_min), " + "round(datos_meteo.temp_max), " + "datos_meteo.precipitaciones " + "FROM meses,provincias,datos_meteo " + "WHERE " + "meses.mes_id=datos_meteo.mes_id " + "AND " + "provincias.provincia_id=datos_meteo.provincia_id"; //reutiliza el comando para enviar la nueva consulta y que //devuelva un ResultSet res = sta.executeQuery(consulta); //imprime el resultado imprimir_ResultSet(res); //cierra los objetos auxiliares res.close(); sta.close();

* imprime en la Salida el resultSet especificado, con los datos de cada * columna tabulados private static void imprimir_ResultSet(ResultSet resultSet) throws SQLException { //nmero de columnas del resultset ResultSetMetaData metaDatos = resultSet.getMetaData(); int columnas = metaDatos.getColumnCount(); //mientras quedan registros por leer en el ResultSet while (resultSet.next()) { //imprime los registros for (int i = 1; i <= columnas; i++) { //seguidos de un tabulador System.out.print(resultSet.getString(i) + "\t"); }

private static void delete_Ejemplo(Connection conn) throws SQLException { System.out.print("\nBorra la provincia 'Valencia' en la tabla " + "'provincias':\n"); //consulta SQL //lnea en blanco String consulta = "DELETE FROM provincias WHERE provincia = System.out.println(); 'Valencia'"; } //comando SQL Statement sta = conn.createStatement(); } //ejecuta la consulta para que muestre las filas eliminadas } System.out.print("\nComo resultado, " + sta.executeUpdate(consulta)

7.5.- Consulta y actualizacin de tipos estructurados.


Imaginemos que tenemos el tipo estructurado direccion: CREATE TYPE direccion AS ( calle varchar, numero integer, codigo_postal varchar); y la tabla afiliados, con una columna basada en el nuevo tipo: CREATE TABLE afiliados(afiliado_id serial, nombre varchar, apellidos varchar, domicilio direccion); Cmo insertamos valores en una tabla con un tipo estructurado? Se puede hacer de dos formas: Pasando el valor del campo estructurado entre comillas simples (lo que obliga a encerrar entre comillas dobles cualquier valor de cadena dentro), y parntesis para encerrar los subvalores separados por comas: INSERT INTO afiliados (nombre, apellidos, direccion). INSERT INTO afiliados (nombre, apellidos, direccion) VALUES ('Onorato', 'Maestre Toledo', '(Calle de Rufino, 56, 98080)');

Mediante la funcin ROW que permite dar valor a un tipo compuesto o estructurado. INSERT INTO afiliados (nombre, apellidos, direccion) VALUES ('Onorato', 'Maestre Toledo', ROW('Calle de Rufino', 56, 98080)); Cmo se referencia una subcolumna de un tipo estructurado? Se emplea la notacin punto, '.' , tras el nombre de la columna entre parntesis, (tanto en consultas de seleccin, como de modificacin) . Por ejemplo: SELECT (domicilio).calle FROM afiliados WHERE (domicilio).codigo _postal=98080 devolvera el nombre de la calle Maestre Toledo. Los parntesis son necesarios para que el gestor no confunda el nombre del campo compuesto con el de una tabla. Y cmo se elimina el tipo estructurado? Se elimina con DROP TYPE, por ejemplo DROP TYPE direccion; En el siguiente enlace puedes descargar un proyecto java que incluye ms ejemplos de todo esto. 7.6.- Consulta y actualizacin de tipos array. PostgreSQL permite especificar vectores multidimensionales como tipo de dato para las columnas de una tabla. Por ejemplo: Declaracin de una columna de tipo vector: nombre_columna tipo_dato[] Declaracin de una columna de tipo matriz multidimensional: nombre_columna tipo_dato[][] En el siguiente ejemplo puedes ver la creacin de una tabla con una columna de tipo array de varchar y como se insertan y consultan valores: //comando sta = conn.createStatement(); sta.execute("DROP TABLE IF EXISTS tareas"); //crea una tabla con una columna matricial de tipo varchar sta.execute("CREATE TABLE tareas(comercial_id integer," + "agenda varchar[][])"); //inserta un registro de dos tareas por da para el comercial nmero 3 //durante dos das (da 1: [0][0],[0][1]; da 2:[1][0],[1][1]) sta.executeUpdate("INSERT INTO tareas VALUES(3," + "'{{\"reunin 9:30\",\"comida 14:30\"}," + "{\"reunin 8:30\",\"cena 22:30\"}}')"); //consulta todas las tarea del segundo da del comercial nmero 3 ResultSet rst = sta.executeQuery("SELECT agenda[2:2] " + "FROM tareas WHERE comercial_id=3"); //muestra el resultado while (rst.next()) { System.out.println(rst.getString(1)); } //consulta la segunda tarea del primer da del comercial nmero 3 rst = sta.executeQuery("SELECT agenda[1][2] " + "FROM tareas WHERE comercial_id=3");

7.7.- Funciones del gestor desde Java.


En PostgreSQL se pueden construir funciones mediante diferentes lenguajes: Funciones de lenguaje de consultas o funciones SQL (Escritas en lenguaje SQL) Funciones de lenguaje procedural (Escritas en lenguaje PL/pgSQL, PL/Java, etc) Funciones de lenguaje de programacin (Escritas en un lenguaje de compilado, como C o C++), Sobre estas funciones debes saber que: Los parmetros de la funcin pueden ser cualquier tipo de dato admitido por el gestor (un tipo bsico, un tipo compuesto, un array o alguna combinacin de ellos). El tipo devuelto puede ser un tipo bsico, un array o un tipo compuesto. Su estructura general tiene la forma: CREATE FUNCION nombre_funcion(tipo_1,tipo_2,...) RETURN tipo AS $$sentencia_sql$$ LANGUAJE SQL Y debes tener en cuenta que: Los argumentos de la funcin SQL se pueden referenciar en las consultas usando la sintaxis $n:, donde $1 se refiere al primer argumento, $2 al segundo, y as sucesivamente. Si un argumento es un tipo compuesto, entonces se usar la notacin '.' para acceder a sus subcolumnas. Por ltimo, al final de la funcin hay que especificar que la funcin se ha escrito en lenguaje SQL mediante las palabras clave LANGUAJE SQL. Por ejemplo, desde Java podemos crear una funcin que convierte un tipo estructurado, por ejemplo el tipo direccion, en una cadena. Para ello, ejecutaremos un comando Statement (sta) con el cdigo SQL de creacin de la funcin: sta.execute (CREATE FUNCTION cadena_direccion(direccion)+ RETURNS varchar AS 'SELECT $1.calle||' '|| CAST($1.numero AS varchar)+ LANGUAGE SQL;) Si una funcin tiene algn parmetro de tipo estructurado, no se podr eliminar el tipo hasta que no se elimine la funcin. Se puede usar DROP C nb_tipo CASCADE para eliminar de manera automtica las funciones que utilizan ese tipo. En el siguiente enlace te puedes descargar un ejemplo donde se crean funciones del gestor y se invocan desde una aplicacin Java. try { package PaquetePrincipal; import java.sql.*; //abre la conexin con la base de datos a la que apunta el url * crea un tipo estructurado, una tabla con el tipo como columna, y una //mediante la contrasea del usuario postgres * funcin sobre el tipo que devuelve una cadena compuesta conn = DriverManager.getConnection(url, "postgres", passwd); public class Main { //comando //URL de la base de datos anaconda sta = conn.createStatement(); //elimina todo lo que va a crearse, si existe previamente. Como la static String url = "jdbc:postgresql://localhost/anaconda"; //contrasea del usuario 'postgres' para acceder a la base de datos funcin anaconda //depende del tipo y se especific CASCADE, se elimina con el tipo static String passwd = "1234"; sta.execute("DROP TABLE IF EXISTS empleados"); public static void main(String[] args) throws SQLException { sta.execute("DROP TYPE IF EXISTS puesto CASCADE"); //conexin //crea el tipo estructurado Connection conn = null; sta.execute("CREATE TYPE puesto AS(nombre varchar," Statement sta = null; + "cargo varchar,sueldo numeric)");

//crea la funcin que transforma el tipo estructurado en una cadena ResultSet rst = sta.executeQuery("SELECT sta.execute("CREATE FUNCTION cadena_puesto(puesto) cadena_puesto(ocupacion) " RETURNS varchar AS $$" + "FROM empleados"); + "SELECT $1.nombre||' como '||$1.cargo||' tiene un sueldo //muestra el resultado de '" while (rst.next()) { + "||CAST(ROUND($1.sueldo,2) AS varchar)||'';$$" System.out.println(rst.getString(1)); + "LANGUAGE SQL"); } //crea la tabla con una columna del tipo creado (columna ocupacion) } catch (SQLException ex) { sta.execute("CREATE TABLE empleados(empleado_id serial," //imprime la excepcin + "ocupacion puesto)"); System.out.println(ex.toString()); //inserta un par de registros } finally { sta.executeUpdate("INSERT INTO empleados (ocupacion)" + "VALUES(ROW('Antonio','Comercial',1450.32));" sta.close(); + "INSERT INTO empleados (ocupacion)" conn.close(); + "VALUES(ROW('Juan','Encargado',1230.48))"); } //consulta el valor de la funcin sobre la columna del tipo } }

8.- Gestin de transacciones. Las transacciones deben cumplir el criterio ACID.


Atomicidad. Se deben cumplir todas las operaciones de la transaccin o no se cumple ninguna; no puede quedar a medias. Consistencia. La transaccin solo termina si la base de datos queda en un estado consistente. Isolation (Aislamiento). Las transacciones sobre la misma informacin deben ser independientes, para que no interfieran sus operaciones y no se produzca ningn tipo de error. Durabilidad. Cuando la transaccin termina el resultado de la misma perdura, y no se puede deshacer aunque falle el sistema. Algunos sistemas proporcionan tambin puntos de salvaguarda (savepoints) que permiten descartar selectivamente partes de la transaccin, justo antes de acometer el resto. 8.1.- Transacciones en una base objeto-relacional. Los SGBDOR gestionan transacciones mediante las sentencias COMMIT (confirmar transaccin) y ROLLBACK (deshacer transaccin). Por tanto, si queremos que un grupo de sentencias se ejecuten como una transaccin, tras abrir una conexin Connection conn; habr que: Poner autocommit=false de la siguiente manera: if (conn.getAutoCommit() ) conn.setAutoCommit( false ); Mediante un bloque try-catch controlar si se deshace conn.rollback o confirma conn.commit la transaccin iniciada con esa conexin. En el siguiente enlace puedes ver como se controlan una secuencia de insert como una transaccin en PostgreSQL. ////////////////////////////////////////////// //////////////////////////////////////////////////////////// // primer boton void deshacer( ) { try{ try { if (con.getAutoCommit() ) con.rollback(); con.setAutoCommit( false ); } stat = con.createStatement(); catch (SQLException e) { //vamos hacer le primer insert System.out.println("Error. No hemos podido deshacer." + String unsql = "insert into persona values ('"+jTextField1.getText() e.getMessage() ); + "', '" + jTextField2.getText() + "', '" } +jTextField3.getText()+ "', '" +jTextField4.getText() } + "' )"; //////////////////////////////////////////////////////////// stat.executeUpdate(unsql); aunque esta un podo desordenado el codigo, espero que dando una } vuelta lo entiendan, sobre la conexion catch(Exception e){ Connection con; // variables de instancia System.out.println(" "+e); Statement stat ; } /** Creates new form ventana */ /////////////////////////////////////////////////////////// public ventana() { // en el constructor // segundo boton initComponents(); try{ try{ String unsql = "insert into persona values ('"+jTextField5.getText() + Class.forName("org.postgresql.Driver"); // este busca el jar de postgres "', '" + jTextField6.getText() + "', '" + jTextField7.getText() + "', '" +jTextField8.getText() + "' )"; con = stat.executeUpdate(unsql); DriverManager.getConnection("jdbc:postgresql://localhost/arq2 con.commit(); tier", "postgres", "1234"); } } catch(Exception e){ catch(Exception e){ deshacer( ); // este metodo es importante System.out.println(" "+e); System.out.println(" "+e); } } } Otro ejemplo public static void executeTransaction(Connection con) { try { //Switch to manual transaction mode by setting //autocommit to false. Note that this starts the first //manual transaction. con.setAutoCommit(false); Statement stmt = con.createStatement(); stmt.executeUpdate("INSERT INTO Production.ScrapReason(Name) VALUES('Wrong size')"); stmt.executeUpdate("INSERT INTO Production.ScrapReason(Name) VALUES('Wrong color')"); con.commit(); //This commits the transaction and starts a new one. stmt.close(); //This turns off the transaction. System.out.println("Transaction succeeded. Both records were written to the database."); } catch (SQLException ex) { ex.printStackTrace(); try { con.rollback();

System.out.println("Transaction failed. No records were written to the database."); } catch (SQLException se) { se.printStackTrace(); } } } 8.2.- Transacciones en un gestor de objetos. Las transacciones en un sistema de objetos puro, se gestionan mediante COMMIT y ROLLBACK . Veamos un ejemplo sencillo con la base de objetos db4o. En Db4o: Siempre se trabaja dentro de una transaccin. Al abrir un ObjectContainer se crea e inicia implcitamente una transaccin. Las transacciones se gestionan explcitamente mediante commit y rollback. La transaccin actual hace commit implcitamente cuando se cierra el ObjectContainer. Por ejemplo, podemos deshacer una transaccin con rollback , restaurando la base de objetos al estado anterior, justo al estado despus del ltimo commit o rollback. En el siguiente ejemplo, al ejecutar db.rollback despus de db.store(p3) y db.store(p4), har que los objetos p3 y p4 no se almacenen en la base de objetos.

Bases de datos xml. 1.- Introduccion. el estndar XML ha sido ampliamente aceptado y adoptado para el almacenamiento e intercambio de informacin 1.1.- Documentos XML centrados en datos y centrados en texto.
los tipos de documentos XML que nos podemos encontrar son: Documentos centrados en datos, Ejemplos: Facturas, Pedidos Ficha de alumno. Documentos centrados en texto. Ejemplos: Libros, Informes, Memorias, Artculos bibliogrficos.

1.2.-Opciones de almacenamiento.
Para almacenar documentos XML tenemos las siguientes opciones: Almacenamiento directo del fichero. Almacenar el documento en una base de datos existente o Directamente como una columna tipo binario grande (BLOB) dentro de una tabla. o Mediante mapeo basado en tablas, o basado en objetos. Almacenar el documento en una base de datos nativa XML. Por tanto, podemos hablar de dos tipos de Sistemas de Bases de Datos que soportan documentos XML: BD XML-compatibles: desglosan un documento XML en su correspondiente modelo relacional o de objetos. BD XML Nativas: respetan la estructura del documento, permiten hacer consultas sobre dicha estructura y recuperan el documento tal y como fue insertado originalmente 2.-Bases de Datos Nativas XML. una NXD o BD XML debe cumplir las siguientes propiedades: Define un modelo lgico de datos XML, El documento XML es la unidad lgica de almacenamiento No tiene ningn modelo de almacenamiento fsico subyacente concreto. Documentos y colecciones. Indexacin. Identificador nico. Consultas. Actualizaciones. Validacin. Soportan transacciones,

2.1.-Estrategias de almacenamiento.
El almacenamiento basado en texto consiste en almacenar el documento XML entero en forma de texto El almacenamiento basado en modelo consiste en definir un modelo de datos lgico, como DOM, para la estructura jerrquica de los documentos XML

2.2.-Colecciones y documentos.
Una coleccin:Es un conjunto de documentos agrupados, normalmente, en funcin de la informacin que contienen. Un documento: Informacin XML

2.3.-Gestores nativos XML comerciales y libres


Gestores nativos XML comerciales o de cdigo propietario son: TaminoXML Server. Es un gestor nativo XML de la empresa SoftwareAG. TEXTML de Isiasoft. Gestores nativos XML libres o de cdigo abierto son: Qizx. Es una base de datos nativa XML escrita en Java. Almacena los datos utilizando una representacin que se basa en el modelo de XPath 2,0. eXist. Utiliza un sistema de almacenamiento propio

3.-Instalacin del gestor Qizx.

3.1.- Gestionar la base de datos XML mediante QizxStudio.

4.- El lenguaje de consultas XQuery. Est basado en el lenguaje XPath, (XML Path Language), Es un lenguaje declarativo, 4.1.- Modelo de datos. El modelo de datos en que se sustenta XQuery es el modelo de datos de XPath. XPath modela un documento
XML como una estructura jerrquica en forma de rbol. El rbol est formado por nodos, y hay siete tipos de nodos: raz, elemento, texto, atributo, espacio de nombres, instruccin de procesamiento y comentario. Los principales nodos de la estructura jerrquica o en rbol en un documento XML son: (puedes verlos en la imagen ampliable superior) Nodo raz o /. Es el primer nodo del documento. Nodo elemento. Cualquier elemento de un documento XML. Cada nodo elemento posee un padre y puede o no tener hijos. En el caso de que no tenga hijos, es un nodo hoja. Nodo texto. Cualquier elemento del documento que no est marcado con una etiqueta de la DTD del documento XML. Nodo atributo. Un nodo elemento puede tener etiquetas que complementen la informacin de ese elemento. Esto sera un nodo atributo.

4.2.- Caminos de localizacin. Hay dos tipos de caminos de localizacin:


Caminos relativos. Caminos absolutos. Los siguientes, son algunos ejemplos de caminos de localizacin: cuadro selecciona los elementos cuadro hijos del nodo contextual. cuadro//titulo selecciona los elementos titulo descendientes de los elementos cuadro hijos del nodo contextual. selecciona todos los elementos hijos del nodo contextual. @ao selecciona el atributo ao del nodo contextual @* selecciona todos los atributos del nodo contextual cuadro[1] selecciona el primer hijo cuadro del nodo contextual cuadro[@ao=1907] selecciona todos los hijos cuadro del nodo contextual que tengan un atributo ao con valor 1907.

4.3.- Primeras consultas XQuery.Una consulta XQuery es una expresin que lee una secuencia de datos en XML y devuelve como
resultado otra secuencia de datos en XML, donde: Una secuencia es un conjunto ordenado de cero o ms tems. Un tem es cualquier tipo de nodo del rbol XML o un valor atmico. Las funciones que se pueden invocar para referirnos a colecciones y documentos dentro de la BD son las siguientes: collection(camino de la coleccin) doc(camino del documento) As por ejemplo: La consulta collection(/Books): devuelve el contenido de la coleccin de ruta absoluta /Books. La consulta doc(/Empresa.xml): devuelve el documento /Empresa.xml completo. La consulta collection(/Books)//book/title devuelve los nodos title de todos los libros (book) de la coleccin /Books Si se utilizan espacios de nombres o namespaces, entonces la consulta anterior se redactara de la siguiente forma: declare namespace t = http://www.qizx.com/namespace/Tutorial; collection(/Books)//t:book/t:title La consulta doc(/Empresa.xml)//nombre devuelve todos los nodos nombre del documento /Empresa.xml

doc("Empresa.xml") collection("/Cursos") devuelve todos los documentos dentro de cursos collection("/Cursos")//curso/nombre consutar nombre de cada curso doc("/Cursos/BasesDeDatosXML.xml")//curso/profesor consultar nombre profesor del cuso BD de xml collection("/Cursos")//curso[plazas=20] cursos con 20 plazas collection("/Cursos")//curso[plazas=20]/nombre nombres de cursos de 20 plazas

4.4.- Expresiones FLWOR.


Se trata de una expresin que permite la unin de variables sobre conjuntos de nodos y la iteracin sobre el resultado. Las diferentes clusulas de una expresin FLWOR son: For. Permite seleccionar los nodos que se quieren consultar, guardndose su valor en una variable (identificador que comienza por $). Al conjunto de valores de la variable se le llama tupla. Let. (opcional). Asocia valores a variables. Where (opcional). Permite filtrar los resultados segn una condicin. Order (opcional). Permite ordenar la secuencia de valores o resultados. Return. Genera los valores de salida o devueltos. for $curso in collection("/Cursos")//curso let $profe:=$curso/profesor where $curso/plazas=20 order by $curso/nombre return $curso/nombre La consulta devuelve los nombres de los cursos con 20 plazas, ordenados por nombre de curso for $curso in collection("/Cursos")//curso where $curso/precio/@cuota="mensual" order by $curso/nombre return $curso/nombre devuelve los nombres de los cursos con cuota mensual (derecha). Como cuota es un atributo del elemento precio, recuerda que se le antecede con un carcter @. for $curso in collection("/Cursos")//curso where $curso/aula=2 order by $curso/nombre return $curso/nombre nombre de cursos que se dan en aula 2 for $curso in collection("/Cursos")//curso let $n:=($curso/nombre) where $curso/aula=2 order by $curso/nombre return data($n) nombre de cursos que se dan en aula 2 pero sin ensear etiquetas

for $curso in collection("/Cursos")//curso let $n:=($curso/nombre) where $curso/aula=2 and $curso/precio[@cuota="mensual"] and $curso/precio[@moneda="euro"] and $curso/precio<50 order by $curso/nombre return data($n) devuelve los nombre de cursos donde el aula 2 , precio de cuota mensual, y precio menor de 50 en euros ordenado por nombre y sin etiquetas

4.5.- XQuery Update Facility.


XQuery Update Facility es una extensin de XQuery que permite la actualizacin de documentos mediante las clusulas insert, delete, replace y rename. El funcionamiento de las clusulas de XQuery Update es el siguiente: insert. Permite la insercin de uno o varios nodos antes (before) o despus (after) del nodo indicado. Tambin se puede insertar al principio (as first into) o al final del documento (as last into). delete. Elimina uno o varios nodos del documento. replace. Tiene dos funciones: Modificar el valor del nodo Modificar el nodo completo rename. Renombra un nodo (elemento, atributo o instrucciones de proceso) sin afectar a su contenido. Eliminar la empresa de id=2 en el documento Empresa.xml: delete node doc(Empresa.xml)//empresa[@id=2] Insertar el nodo tipoAccesible/tipo al final del documento /Aulas/aula3 insert node tipoAccesible/tipo as last into doc(Aulas/aula3.xml)//aula (:Sustituye el nombre de la empres de id=1 por "EmpresaAlfa" :) replace value of node doc("Empresa.xml")//empresa[@id="1"]/nombre with "EmpresaAlfa" (:insertar el nodo <gerente> en empresa de id=1:) insert node <gerente>Pedro Golondrino Verde</gerente> as last into doc("Empresa.xml")//empresa[@id="1"] (: cambiar el nombre del nodo <edificio> de cada documento de la coleccin Aulas por <lugar>:) for $x in collection("/Aulas/*")//aula/edificio return rename node $x as "lugar" (:Elimina el nodo <gerente> de empresa id=1 :) delete node doc("/Empresa.xml")//empresa[@id="1"]/gerente (:Inserta dos nodos :) <telefono>952123456</telefono> insert node <email>empresabeta@dominiobeta.es</email> <empresa id="2"> <web>www.dominiobeta.es</web> <nombre>Empresa Z</nombre> </empresa> <cif>B32674129</cif> <direccion> C\ Las Marinas 25</direccion> as last into doc("Empresa.xml") <localidad>Granada</localidad> borrar nodo con id=2 <provincia>Granada</provincia> delete node doc("Empresa.xml")//empresa[@id=2] <cpostal>18004</cpostal> remplazar valor de un nodo <telefono>952245689</telefono> replace value of node <email>empresaz@dominioz.es</email> doc("Empresa.xml")//empresa[@id="1"]/email <web>www.dominioz.es</web> with "EmpresaAlfa@dominiox.es", </empresa> replace node doc("Empresa.xml")//empresa[@id="1"]/telefono after doc("Empresa.xml")//empresa[1], with <telefono>888888</telefono> (: renombre el nodo 'empresa/web' poniendolo en mayusculas:) insert node for $x in doc("Empresa.xml")//empresa/web <empresa id="4"> return <nombre>Empresa Beta</nombre> rename node $x <cif>B12374129</cif> as upper-case(name($x)) <direccion> C\ Golondrina 45</direccion> (:Inserta nodo tipo en el documento aula3 :) <localidad>Granada</localidad> insert node <provincia>Granada</provincia> <tipo>Accesible</tipo> <cpostal>18004</cpostal> as last into doc("Aulas/aula3.xml")//aula

5.- Trabajar con colecciones y documentos desde Java. El API principal para trabajar con una base de datos XML de Qizx en un entorno de desarrollo Java, la proporciona el paquete com.qizx.api, A continuacin te indicamos algunas de las clases e interfaces del paquete com.qizx.api de ms inters: Interface Library. Representa una BD XML o una conexin a una BD XML. Interface LibraryManager. Representa el gestor de las BDs. Permite gestionar grupos de BDs XML. Clase Configuration. Inicializa y configura un LibraryManager, permitiendo su creacin, apertura, etc.. Interface LibraryMember. Representa un miembro de una BD XML, esto es, coleccin o documento. Algunas sub_interfaces son: Collection, Document, NonXMLDocument. Interface Collection. Para gestionar colecciones y sub_colecciones que contienen documentos XML. Interface Document. Representa documentos XML bien formados y almacenados en una BD XML. Al ser un LibraryMember (miembro de una Library), puede tener propiedades (metadatos) que pueden consultarse. Clase Index. Para crear ndices en una BD XML y especificar sus parmetros. El paquete org.xml.sax. Proporciona las clases e interfaces para el API SAX, que es un componente de la API de Java para el procesamiento de documentos XML, como por ejemplo el interface XMLReader. El paquete com.qizx.xdm. Proporciona clases e interfaces para el anlisis y procesamiento de documentos XML, como por ejemplo la clase DocumentParser.

5.1.- Creacin de la BD XML. Establecer conexiones.


Crear la BD XML. El mtodo createLibrary(String nombreBD, File directorioBD) crea la BD de nombre nombreBD localizada fsicamente en el directorio directorioBD, directorio que debe existir y estar vaco. Si el parmetro directorioBD se pasa como valor null, la BD se crear en un subdirectorio del grupo con nombre nombreBD. Establecer conexin. El mtodo openLibrary(String nombreBD) abre una nueva sesin o conexin a la BD de nombre nombreBD. //Metodo que obtiene la conexion a una bd XML private static Library obtenerBD(LibraryManager bdManager, String bdNombre) throws QizxException { //Abre una conexion a la BD XML de nombre bdNombre Library bd = bdManager.openLibrary(bdNombre); //Si no se ha abierto la BD (porque no existe) if (bd == null) { System.out.println("Creando BD XML '" + bdNombre + "'..."); //Crea la BD XML bdManager.createLibrary(bdNombre, null); //Abre una conexion a la BD creada bd = bdManager.openLibrary(bdNombre); } //devuelve la conexion return bd; }

5.2.- Cerrar conexiones.


Cerrar una conexin. El mtodo Library.close() cierra la conexin a una BD particular. Si ha comenzado alguna transaccin, no se podr invocar close(), solo se podr invocar commit() o rollback(), por lo que antes de invocar close(), debemos comprobar mediante el mtodo Library.isModified() si la base de datos est inmersa en una transaccin. Cerrar todas las conexiones. El mtodo LibraryManager.closeAllLibraries(int tiempo) cierra todas las conexiones a BD del mismo grupo y libera los recursos. Mediante el parmetro int tiempo, se le puede indicar el tiempo en milisegundos que debe esperar el sistema antes de realizar la desconexin de aquellas Library //Metodo que cierra la conexion a la base de datos private static void cerrar(Library bd, LibraryManager bdManager) throws QizxException { //Si la base de datos esta inmersa en una transaccion if (bd.isModified()) { //deshace los cambios realizados por la transaccion bd.rollback(); } //cierra la conexion a la base de datos bd bd.close(); //cierra las bases de datos del grupo despues de 10000 ms bdManager.closeAllLibraries(10000 /*ms*/); } 5.3.- Crear colecciones. createCollection(String ruta). Mtodo de la interface Library. Crea una coleccin en la BD, cuya posicin dentro de la base de datos es la que indica el parmetro ruta, siendo ruta una camino o path absoluto en la BD. createChildCollection(String nombre). Mtodo de la interface Collection. Crea una sub_coleccin dentro de una coleccin, denominada nombre. Collection coleccion = bd.getCollection(ruta); //si no existe la coleccion, crea la coleccion if (coleccion == null) { System.out.println("Creando coleccion '" + ruta + "'..."); coleccion = bd.createCollection(ruta); } 5.4.- Aadir documentos. ImportDocument(String documentoRuta, Tipo fuente).Mtodo de la interface Library. Existen diferentes mtodos para importar documentos XML a una BD XML, que se diferencian fundamentalmente en el Tipo de los documentos fuente indicados como segundo parmetro: java.io.File, java.net.URL, org.xml.sax.InputSource, etc. En todos los casos, la fuente debe contener un documento XML bien formado. Uno de estos mtodos es:

importDocument(String documentoRuta, File fichero). Importa un documento a la base de datos mediante un anlisis o parsing de un fichero de texto XML ubicado en fichero. Si ya existe un documento con la misma ruta en la BD, se sustituye por los nuevos contenidos. Si la coleccin que contiene este documento no existe, se crea automticamente. System.out.println("Importando '" + fichero + "' como documento '" + ruta + "'..."); //importa a bd, en la posicion indicada por ruta, el documento XML cuyo texto XML esta en fichero bd.importDocument(ruta, fichero); Qizx incluye la biblioteca resolver.jar, conocida como resolucin del catlogo XML, que forma parte del proyecto Apache XML Commons, de manera que todos los mtodos Library.importDocument() son catlogos XML habilitados. Por lo tanto, basta con especificar el correspondiente importDocument() y dejar que mediante resolver.jar se realice la resolucin, anlisis o parsing.

5.5.- Creacin de una BD XML e importacin de colecciones y documentos.


Otros mtodos tiles al llenar una Library con colecciones y documentos, o bien trasladar colecciones y documentos de una Library a otra son los siguientes: Library.getMember(String rutaAbsoluta): devuelve el miembro especficado en esa ruta de la BD, un LibraryMember (documento o coleccin), o bien null si no existe ese miembro. Library.getDocument(String rutaAbsoluta): devuelve el documento especficado en esa ruta de la BD, un Document o bien null si no existe. Library.getCollection(String rutaAbsoluta): devuelve coleccin especficada en esa ruta de la BD, una Collection o bien null si no existe. Library.getName(): devuelve el nombre de la Library o base de datos. LibraryMember.getPath(): devuelve la ruta completa del miembro en esa BD. LibraryMember.getName(): devuelve el nombre del miembro dentro de su coleccin sin '/', excepto si es la coleccin rarz. LibraryMember.isDocument(): devuelve verdadero si el miembro es un documento. LibraryMember.isCollection(): devuelve verdadero si el miembro es una coleccin. Collection.getChildren(): devuelve un iterador, un LibraryMemberIterator, sobre los miembros de esa coleccin (documentos o colecciones). LibraryMemberIterator.iter.moveToNextMember(): devuelve verdadero si accede al siguiente miembro. LibraryMemberIterator.getCurrentMember(): devuleve el mimbro actual.

/* * To change this template, choose Tools | Templates * and open the template in the editor. */ package poner; import java.io.File; import java.io.FileFilter; /** * * @author IMCG */ //Clase que implementa un filtro para extensiones de ficheros class FiltroFichero implements FileFilter { //array para guardar las extensiones precedidas por '.' private String[] sufijo; private boolean noCoincide; public FiltroFichero(String patron) { noCoincide = false; //Guarda las extensiones de los ficheros a procesar String[] extension = patron.split(",");

sufijo = new String[extension.length]; //Guarda cada extensin, precedida por punto for (int i = 0; i < extension.length; ++i) { String ext = extension[i]; sufijo[i] = "." + ext; } } @Override public boolean accept(File file) { if (file.isDirectory()) { return true; } String nombre = file.getName(); boolean res = false; for (int i = 0; i < sufijo.length; ++i) { if (nombre.endsWith(sufijo[i])) { res = true; break; } } return noCoincide ? !res : res; } }

//Interfaces y clases para gestionar la BD XML, las colecciones y documentos import com.qizx.api.Collection; import com.qizx.api.Configuration; import com.qizx.api.Library; import com.qizx.api.LibraryManager; import com.qizx.api.LibraryMember; import com.qizx.api.QizxException; //Interfaces y clases para el procesamiento y anlisis de documentos XML import org.xml.sax.SAXException; //Interfaces y clases para gestionar archvios y flujos de datos import java.io.File; import java.io.FileFilter; import java.io.IOException; private static String directorioGrupoRoot = "c:\\dbxml"; //Nombre de Bilioteca o BD (Library): Tutorial private static String bdNombre = "Tutorial"; //ruta raz colecciones de la BD o Library private static String ruta = "/"; //ruta de las colecciones origen a importar private static String datosOrigenRoot ="C:\\qizx\\docs\\samples\\book_data\\"; //array con nombres de las colecciones origen a importar private static String[] datosOrigenNombre = {"Author Blurbs", "Authors", "Books", "Publishers"}; //filtro de extensiones de los ficheros (documentos) a importar: xml y //Valores que se establecen para la creacin de la base de datos XML xhtml que private static String extensionFiltro = "xml,xhtml"; //se crear y los colecciones que contendr //ruta del Grupo de bases de datos (Library Group):C:\dbxml if (directorioGrupo.exists()) { return Configuration.openLibraryGroup(directorioGrupo); //si no existe el directorio, intenta crearlo, y devuelve el manejador //LibraryManager asociado } else { if (!directorioGrupo.mkdirs()) { throw new IOException("no se puede crear directorio '" + directorioGrupo + "'"); } System.out.println("creando el Grupo de BDs en '" + directorioGrupo + "'..."); return Configuration.createLibraryGroup(directorioGrupo); } }

private static LibraryManager obtenerBDManager(File directorioGrupo) throws IOException, QizxException { //objeto para gestionar el directorio asociado al grupo de bibliotecas //si existe el directorio asociado al grupo, devuelve el manejador //LibraryManager asociado

//Mtodo que obtiene la conexin a una bd XML private static Library obtenerBD(LibraryManager bdManager, String bdNombre) } throws QizxException { //Abre una conexin a la BD XML de nombre bdNombre

Library bd = bdManager.openLibrary(bdNombre); //Si no se ha abierto la BD (porque no existe) if (bd == null) { System.out.println("Creando BD XML '" + bdNombre + "'..."); //Crea la BD XML bdManager.createLibrary(bdNombre, null); //Abre una conexin a la BD creada bd = bdManager.openLibrary(bdNombre); } //devuelve la conexin return bd;

private static void llenar(Library bd, File fichero, FileFilter filtro, String ruta) throws IOException, QizxException, SAXException { if (fichero.isDirectory()) { //si es directorio //obtiene la coleccin de la BD bd situada en esa ruta Collection coleccion = bd.getCollection(ruta); //si no existe la coleccin, crea la coleccin if (coleccion == null) { System.out.println("Creando coleccin '" + ruta + "'..."); coleccion = bd.createCollection(ruta); } METODO MAIN public static void main(String[] args) throws IOException, QizxException, SAXException { //variables locales String nombre; //filtro de ficheros FileFilter filtro = new FiltroFichero(extensionFiltro); //crea el objeto file directorioGrupo apuntando a esa ruta File directorioGrupo = new File(directorioGrupoRoot); //obtiene un grupo de bibliotecas LibraryManager bdManager = obtenerBDManager(directorioGrupo); //crea una bilbioteca o BD Library bd = obtenerBD(bdManager, bdNombre); //crea objeto miembro con la ruta absoluta LibraryMember miembroBD = bd.getMember(ruta);

//Guarda en files, los ficheros con extensin coincidente en el filtro File[] files = fichero.listFiles(filtro); if (files == null) { throw new IOException("Error al listar directorio '" + fichero + "'"); } //para cada fichero lo incluye en su correspondiente coleccin de la BD for (int i = 0; i < files.length; ++i) { File file = files[i]; llenar(bd, file, filtro, ruta + "/" + file.getName()); } //si no es un directorio, lo importa como documento XML analizndolo } else { System.out.println("Importando '" + fichero + "' como documento '" + ruta + "'..."); //importa a bd, en la posicin indicada por ruta, el documento XML // cuyo texto XML est en fichero bd.importDocument(ruta, fichero); } }

try { //para cada miembro for (int i = 0; i < datosOrigenNombre.length; i++) { //accede a la coleccin fuente para guardar su ruta y nombre File fichero = new File(datosOrigenRoot + datosOrigenNombre[i]);

//si es un miembro coleccin, guarda en 'nombre' su nombre antecedido por / if (miembroEsColeccion) { nombre = ruta + datosOrigenNombre[i]; //el mtodo llenar() vincula a la base de datos bd, la coleccion //localizada en 'fichero', denominada 'nombre', conteniendo los //documentos segn filtro llenar(bd, fichero, filtro, nombre); } } //comprueba si el miembro es una coleccin vlida System.out.println("Confirmados cambios..."); boolean miembroEsColeccion = (miembroBD != null && //Confirma las operaciones de la transaccin miembroBD.isCollection()); bd.commit(); } catch (Exception ex) { //si no es una coleccin, cierra la BD bd y el grupo bdManager, y System.err.println(ex); //muestra mensaje System.exit(1); if (!miembroEsColeccion) { } finally { cerrar(bd, bdManager); //cierra o realiza la desconexin de la BD bd System.out.println("'" + ruta + "', no existe o no es una coleccin"); cerrar(bd, bdManager); } } } METODO CERRAR CONEXIN A BD //mtodo que cierra la conexin a la base de datos private static void cerrar(Library bd, LibraryManager bdManager) throws QizxException { //Si la base de datos est inmersa en una transaccin if (bd.isModified()) { //deshace los cambios realizados por la transaccin bd.rollback(); } //cierra la conexin a la base de datos bd bd.close(); //cierra las bases de datos del grupo despus de 10000 ms bdManager.closeAllLibraries(10000 /*ms*/); } }

5.6.- Eliminar colecciones y documentos. Para eliminar colecciones y documentos se pueden utilizar los mtodos:
deleteMember(String ruta). Mtodo de la interface Library. Elimina el miembro de la BD indicado mediante el parmetro ruta, que ser la ruta absoluta dentro de la BD. Si se trata de una coleccin, elimina tambin de forma recursiva todos sus documentos y sub_colecciones. delete(). Mtodo de la interface LibraryMember. Es equivalente al mtodo anterior, es decir, es equivalente a Library.deleteMember(getPath()). Y cmo eliminar toda la base de datos? Para ello, puedes utilizar: el mtodo deleteLibrary(String bdNnombre) de la interface LibraryManager, que elimina fsicamente la BD. package delete; if (!bdManager.deleteLibrary(bdNombre)) { /** System.out.println("Base de datos '" + bdNombre + "' no * encontrada"); * @author IMCG } */ bdManager.closeAllLibraries(10000 /*ms*/); import com.qizx.api.Configuration; } else { import java.io.File; //Abre la base de datos import com.qizx.api.QizxException; Library bd = bdManager.openLibrary(bdNombre); import com.qizx.api.Library; try { //borra las colecciones especificadas import com.qizx.api.LibraryManager; public class Delete { for (int i = 0; i < coleccionNombre.length; i++) { ruta = coleccionNombre[i]; //ruta del Grupo de bibliotecas: if (bd.deleteMember(ruta)) { private static String directorioGrupoRoot = "c:\\dbxml"; System.out.println("Borrando coleccin '" + ruta //Nombre de la BD o Lidrary + "' de la BD '" + bdNombre + "'..."); private static String bdNombre = "Libros"; }else //colecciones a borrar System.out.println("Coleccin '" + ruta + "' de la BD '" private static String[] coleccionNombre = {"/Authors","/Books"}; + bdNombre + "' no encontrada"); //sin nombres, borra toda la base de datos... } // private static String[] coleccionNombre = {}; System.out.println("Confirmando los cambios..."); bd.commit(); /**************************************************************************** } finally { * //cierra la base de datos * @param args cerrar(bd, bdManager); * @throws QizxException } */ } public static void main(String[] args) throws QizxException { } //mtodo que cierra la conexin a la base de datos //variables locales private static void cerrar(Library bd, LibraryManager bdManager) String ruta; throws QizxException { //si la base de datos est inmersa en una transaccin //crea el objeto file 'directorioGrupo' apuntando a esa ruta if (bd.isModified()) { File directorioGrupo = new File(directorioGrupoRoot); //deshacer las opersciones de la transaccin bd.rollback(); // Conexin o apertura del gestor del grupo; } LibraryManager bdManager = //cierra la conexin a la base de datos Configuration.openLibraryGroup(directorioGrupo); bd.close(); //cierra todas las bases de datos del grupo en 10000 ms //si no se especifica ninguna coleccin bdManager.closeAllLibraries(10000); if (coleccionNombre.length == 0) { } //borra toda la base de datos } System.out.println("Borrando toda la base de datos '" + bdNombre + "'...");

5.7.- Consultar documentos. La respuesta es s, pero ser necesario realizar los siguientes pasos para procesar una consulta desde
Java: Compilar la consulta o expresin XQuery mediante el mtodo Library.compileExpression(). Si la compilacin se realiza sin errores (CompilationException), devolver un objeto Expression. Evaluar la expresin o consulta compilada mediante el mtodo Expression.evaluate(). Si la evaluacin se realiza sin errores (EvaluationException), devolver el resultado en forma de un ItemSequence. Iterar sobre la secuencia obtenida. Un ItemSequence permite iterar sobre una secuencia de Items, donde un Item es un valor atmico o un nodo XML. Un iterador siempre tiene un mtodo moveToNextItem() que mueve la posicin del cursor al siguiente elemento y un getCurrentItem() que devuelve el elemento encontrado en la posicin actual del cursor. Por tanto, los pasos anteriores suponen las siguientes sentencias de cdigo: Expression exprcompilada = bd.compileExpression(scriptConsulta); ItemSequence resultado = exprcompilada.evaluate(); while (resultado.moveToNextItem()) { Item resul = resul.getCurrentItem(); /* Manipular resultado*/ } Otros mtodos tiles en el procesamiento de una consulta son los siguientes: El mtodo Item.getNode() que obtiene el valor de un nodo XML (objeto tipo Node) tras la evaluacin de una consulta XQuery compilada. El mtodo XMLSerializer.serializeToString() que permite serializar como una cadena un nodo XML. El mtodo Expression.bindImplicitCollection() que permite escribir consultas con rutas o paths las cuales no van precedidas por las expresiones collection(XXX) o doc(YYY). Por ejemplo, usando bindImplicitCollection() se puede utilizar como expresin: //book/title en vez de collection(/Books)//book/title El mtodo Expression.bindVariable() que permite vincular una secuencia de Items a una variable. package query; //para manejar BD XML //Para manejar ficheros y stream import com.qizx.api.Library; import java.io.IOException; import com.qizx.api.LibraryManager; import java.io.File; import com.qizx.api.Configuration; import java.io.FileInputStream; //para manejar excepciones import java.io.InputStreamReader; import com.qizx.api.QizxException;

import com.qizx.api.Message; import com.qizx.api.CompilationException; //para gestionar consultas XQuery import com.qizx.api.Item; import com.qizx.api.ItemSequence; import com.qizx.api.Node; import com.qizx.api.Expression; import com.qizx.api.util.XMLSerializer; /****************************************************************************** * clase para ejecutar scripts de consulta XQuery en una BD de XML * * @author IMCG */ public class Query { //ruta del Grupo de BD private static String directorioGrupoRoot = "c:\\dbxml"; //Library o base de datos private static String bdNombre = "Cursillos"; //"Tutorial"; //ruta donde se almacenan los scripts con consultas XQuery private static String directorioScriptsRoot = "C:\\BDCursillosXML\\cursillos_query\\"; //directorio de scripts BD Tutorial // "C:\\qizx\\docs\\samples\\book_queries\\"; //nombres de los scripts con consultas XQuery - ficheros .xq private static String[] scriptNombre = { "10CursosAula2Nombre_flwor.xq", "11CursosAula2Condiciones_flwor.xq"}; //Si cambias a la BD Tutorial, los scripts son {"7.xq", "8.xq"};

//mensajes de error devueltos tras la compilacin Message[] messages = e.getMessages(); for (int i = 0; i < messages.length; ++i) { System.out.println(messages[i].toString()); } throw e; } //devuelve consulta compilada return expr; } //mtodo que evala la consulta y muestra un rango de resultados entre min y max private static void evaluarExpression(Expression expr, int min, int max) throws QizxException { //evala la consulta compilada obteniendo un ItemSequence ItemSequence results = expr.evaluate(); if (min > 0) { results.skip(min); } XMLSerializer serializer = new XMLSerializer(); serializer.setIndent(2); int count = 0; while (results.moveToNextItem()) { Item result = results.getCurrentItem(); //genera el nmero de orden para cada resultado de la consulta System.out.print("[" + (min + 1 + count) + "] "); //imprime uno de los resultados de la consulta mostrarResultado(serializer, result); System.out.println(); ++count; //si ya se han imprimido un total de max resultados, no imprime ms if (count >= max) { break; } } System.out.flush(); } //Mtodo para mostrar el resultado private static void mostrarResultado(XMLSerializer serializer, Item result) throws QizxException { //Si no es un nodo del rbol XML, escribe el resultado como cadena if (!result.isNode()) { System.out.println(result.getString()); return; } //obtiene el nodo XML del resultado, el Item Node node = result.getNode(); //prepara la serializacin de otro arbol XML serializer.reset(); //El mtodo XMLSerializer.serializeToString se utiliza para obtener la //representacin de cadena de un nodo. String xmlForm = serializer.serializeToString(node); //Imprime el nodo del resultado como cadena System.out.println(xmlForm); } //mtodo que cierra la conexin a la base de datos private static void cerrar(Library bd, LibraryManager bdManager) throws QizxException { //si la basede datos esta inmersa en una transaccin, deshacer los cambios if (bd.isModified()) { bd.rollback(); } //cerrar conexin con base de datos bd.close(); //cerrar las bases de datos del grupo dentro de 100000 ms bdManager.closeAllLibraries(10000); } //mtodo que devuelve la consulta XQuery (almacenada en fichero file) //en una cadena private static String cargaScript(File file) throws IOException { //Obtiene el contenido del fichero

public static void main(String[] args) throws IOException, QizxException { //variables para controlar el rango de resultados de la consulta que se //imprimen int min = 0; int max = Integer.MAX_VALUE; //fichero para recoger cada script XQuery de consulta File scriptFile; //objeto file 'directorioGrupo' apuntando a la ruta del Library Group File directorioGrupo = new File(directorioGrupoRoot); // Conexin o apertura del gestor del grupo LibraryManager bdManager = Configuration.openLibraryGroup(directorioGrupo); //Conexin a la BD Library bd = bdManager.openLibrary(bdNombre); try { //Para cada script con consulta XQuery for (int i = 0; i < scriptNombre.length; ++i) { //recoge la ruta del fichero de script con consulta XQuery scriptFile = new File(directorioScriptsRoot + scriptNombre[i]); //mensaje indicando el script XQuery que se ejecutar System.out.println("Ejecutando '" + scriptFile + "'..."); //carga el contenido del script XQuery en una cadena String consultaXquery = cargaScript(scriptFile); //imprime la expresin de consulta XQuery System.out.println("---\n" + consultaXquery + "\n---"); //compila la consulta, almacenado resultado en expr Expression expr = compileExpression(bd, consultaXquery); //evala la consulta para mostrar resultados en el rango [min, max] evaluarExpression(expr, min, max); } } finally { //cierra conexin con BD cerrar(bd, bdManager); } }

//Mtodo para compilar la consulta controlando errores private static Expression compileExpression(Library bd, String consultaXquery) throws IOException, QizxException { Expression expr; try { expr = bd.compileExpression(consultaXquery); } catch (CompilationException e) {

InputStreamReader in = if (count > 0) { new InputStreamReader(new FileInputStream(file), "UTF-8"); build.append(chars, 0, count); //cadena para construir la cadena resultante } } StringBuilder build = new StringBuilder(); } finally { //array de tamao suficiente para alamcenar los caracteres del script char[] chars = new char[8192]; in.close(); int count; } try { return build.toString(); //mientras hay caracteres en el contenido del fichero } //los aade a la cadena } while ((count = in.read(chars, 0, chars.length)) != -1) {

5.8.- Actualizar documentos.


Aunque dependiendo del sistema de BD XML pueden existir diferentes formas de actualizar documentos, la manera ms sencilla de hacerlo es mediante Update XQuery, la extensin del lenguaje XQuery que permite inserciones, eliminaciones y modificaciones de nodos de los documentos XML. En el siguiente enlace dispones de un ejemplo detallado de actualizacin XQuery desde una aplicacin Java. La actualizacin consiste en aadir dos nodos empresa al documento /Empresa.xml de la BD Cursillos. //compila la consulta de actualizacin package edit; Expression expr = compilaExpression(bd, script, queryRoot); import com.qizx.api.ItemSequence; import java.io.IOException; //evala la consulta compilada import java.io.File; evaluaExpression(expr, bd); import java.io.FileInputStream; } finally { import java.io.InputStreamReader; cerrar(bd, bdManager); import com.qizx.api.QizxException; } import com.qizx.api.Message; } import com.qizx.api.CompilationException; /**************************************************************************** import com.qizx.api.Configuration; * Compila la consulta import com.qizx.api.Expression; * import com.qizx.api.LibraryMember; * @param bd: base de datos import com.qizx.api.Library; * @param script: script con consulta de actualizacin import com.qizx.api.LibraryManager; * @param queryRoot: camino localizacin consulta * @return expression compilada /****************************************************************************** * @throws IOException * clase para ejecutar scripts de actualizacin XQuery * @throws QizxException * */ * @author IMCG private static Expression compilaExpression(Library bd, */ String script, LibraryMember queryRoot) public class XUpdate { throws IOException, QizxException { Expression expr; //ruta del Grupo de BD try { private static String directorioGrupoRoot = "c:\\dbxml"; expr = bd.compileExpression(script); //Base de Datos } catch (CompilationException e) { private static String bdNombre = "Cursillos"; Message[] messages = e.getMessages(); //fichero con script de actualizacin private static String ficheroScriptRoot = for (int i = 0; i < messages.length; ++i) { "C:\\BDCursillosXML\\cursillos_query\\12update_insert.xq"; System.out.println(messages[i].toString()); // "C:\\BDCursillosXML\\cursillos_query\\13update_delete.xq"; } // "C:\\BDCursillosXML\\cursillos_query\\14update_replace_node_value.xq"; throw e; // } "C:\\BDCursillosXML\\cursillos_query\\15update_rename_varios_nodos.x q"; if (queryRoot != null) { /**************************************************************************** expr.bindImplicitCollection(queryRoot); * } * @param args return expr; * @throws IOException } * @throws QizxException */ /**************************************************************************** public static void main(String[] args) * Evala la expresin compilada throws IOException, QizxException { * * @param expr: expresin compilada //variables locales * @param library: base de datos LibraryMember queryRoot=null; * @throws QizxException File scriptFile; */ //crea el objeto file apuntando a esa ruta private static void evaluaExpression(Expression expr, Library File directorioGrupo = new File(directorioGrupoRoot); library) throws QizxException { // Conexin o apertura del gestor del grupo de BD /*ItemSequence results =*/ LibraryManager bdManager = ItemSequence evaluate = expr.evaluate(); Configuration.openLibraryGroup(directorioGrupo); // confirmar cambios en BD library.commit(); //abre conexin a la BD } Library bd = bdManager.openLibrary(bdNombre); /**************************************************************************** try { * Cierra la base d edatos y el su grupo scriptFile = new File(ficheroScriptRoot); * @param bd * @param bdManager //carga el contenido del fichero de script en una cadena * @throws QizxException String script = cargarScript(scriptFile); */ System.out.println("---\n" + script + "\n---"); private static void cerrar(Library bd, LibraryManager bdManager) throws QizxException {

bd.close(); bdManager.closeAllLibraries(10000 /*ms*/); }

int count; try { while ((count = in.read(chars, 0, chars.length)) != -1) { if (count > 0) { build.append(chars, 0, count); } } } finally { in.close(); } return build.toString();

/**************************************************************************** * Carga el script de consulta de actualizacin en una cadena */ private static String cargarScript(File file) throws IOException { InputStreamReader in = new InputStreamReader(new FileInputStream(file), "UTF-8");

} } StringBuilder build = new StringBuilder(); char[] chars = new char[8192]; El siguiente ejemplo actualiza un documentos de la coleccin Authors, insertando un nuevo pseudnimo al autor que se pasa como parmetro al script. El script de actualizacin est almacenado dentro del directorio de instalacin de Qizx: docs\samples\programming\edit\pseudonym.xq package update_2; //Para cada elemento en varName import java.io.IOException; for (int i = 0; i < length; i++) { import java.io.File; //construye un QName vlido o null import java.io.FileInputStream; varQName[i] = procesaQName(bd, varName[i]); import java.io.InputStreamReader; } import com.qizx.api.QizxException; //comprueba la existencia de la coleccin import com.qizx.api.Message; if (coleccionNombre != null) { import com.qizx.api.CompilationException; queryRoot = bd.getMember(coleccionNombre); import com.qizx.api.Configuration; if (queryRoot == null) { import com.qizx.api.QName; cerrar(bd, bdManager); import com.qizx.api.Expression; System.out.println("'" + coleccionNombre + "no encontrada"); import com.qizx.api.LibraryMember; } import com.qizx.api.Library; } import com.qizx.api.LibraryManager; try { /****************************************************************************** scriptFile = new File(ficheroScriptRoot); //carga el script de actualizacin * clase para ejecutar scripts de actualizacin Update XQuery String script = cargarScript(scriptFile); */ public class Main { System.out.println("---\n" + script + "\n---"); //compila la expresin de consulta //ruta del Grupo de bibliotecas: db Expression expr = compilarExpresion(bd, script, queryRoot, private static String directorioGrupoRoot = "c:\\dbxml"; varQName, varValue); //Bilioteca o base de datos: Tutorial //evala la expresin compilada private static String bdNombre = "Tutorial"; evaluarExpresion(expr, bd); //nombre de la coleccin que se quiere modificar } finally { private static String coleccionNombre = "Authors"; cerrar(bd, bdManager); } //Ruta del script de actualizacin } //recuerda corregir, si hay algn QName con Q minscula y poner a mayscula private static String ficheroScriptRoot = //Mtodo para procesar y generar un QName vlido o null "C:\\qizx\\docs\\samples\\programming\\edit\\pseudonym.xq"; private static QName procesaQName(Library bd, String qName) { int length = qName.length(); //nombre de las variables requeridas por el script private static String[] varName = {"authorName", "pseudo"}; if (length == 0) { //valores de las varibales requeridas por el script return null; private static String[] varValue = {"Philip Jos Farmer", "Kilgort } Trout"}; //para ejecutar este ejemplo varias veces hay que poner un pseudnimo int pos; //distinto cada vez, porque no se aceptan pseudnimos duplicados; o if (qName.charAt(0) == '{' && (pos = qName.lastIndexOf('}')) > 0) { bien, if (pos + 1 == length) { //volver a colocar los datos originates ejecutando Qizx_put return null; */ } public static void main(String[] args) throws IOException, QizxException { String uri = qName.substring(1, pos); String localPart = qName.substring(pos + 1); //variables locales int length; if (uri.length() == 0) { File scriptFile; return bd.getQName(localPart); LibraryMember queryRoot = null; } else { //array de variables QName - nombre calificado return bd.getQName(localPart, uri); QName[] varQName; } } else { //crea el objeto file apuntando a esa ruta if (qName.startsWith("xml:")) { File directorioGrupo = new File(directorioGrupoRoot); String localPart = qName.substring(4); return bd.getQName(localPart, // Conexin o apertura del gestor del grupo de BD "http://www.w3.org/XML/1998/namespace"); LibraryManager bdManager = } else { Configuration.openLibraryGroup(directorioGrupo); return bd.getQName(qName); } //conexin a la BD } Library bd = bdManager.openLibrary(bdNombre); } length = varName.length; //crea tantos objetos QName como elementos tenga el array varName varQName = new QName[length]; /**************************************************************************** * Compila la expresin de actualizacin */

private static Expression compilarExpresion(Library bd, String script, LibraryMember queryRoot, QName[] varNames, String[] varValues) throws IOException, QizxException { Expression expr; try { expr = bd.compileExpression(script); } catch (CompilationException e) { Message[] messages = e.getMessages(); for (int i = 0; i < messages.length; ++i) { System.out.println(messages[i].toString()); } throw e; } if (queryRoot != null) { expr.bindImplicitCollection(queryRoot); } if (varNames != null) { for (int i = 0; i < varNames.length; ++i) { expr.bindVariable(varNames[i], varValues[i], /*type*/ null); } } return expr; } /**************************************************************************** * Evala la consulta de actualizacin compilada */ private static void evaluarExpresion(Expression expr, Library library) throws QizxException { /*ItemSequence results =*/ expr.evaluate(); //confirma transaccin

library.commit(); } /**************************************************************************** * Cierra la base de datos y todas las del grupo */ private static void cerrar(Library bd, LibraryManager bdManager) throws QizxException { bd.close(); bdManager.closeAllLibraries(10000 /*ms*/); }

/**************************************************************************** * Carga el script de actualizacin */ private static String cargarScript(File file) throws IOException { InputStreamReader in = new InputStreamReader(new FileInputStream(file), "UTF-8"); StringBuilder buffer = new StringBuilder(); char[] chars = new char[8192]; int count; try { while ((count = in.read(chars, 0, chars.length)) != -1) { if (count > 0) { buffer.append(chars, 0, count); } } } finally { in.close(); } return buffer.toString(); } }

6.- Indexacin.
De manera predeterminada, Qizx indexa la mayor parte de la informacin disponible en documentos XML: elementos, atributos, nodos, y texto completo. Esto se realiza automticamente. Qizx soporta los siguientes tipos de ndices: ndices elemento. Dado un nombre de elemento, este ndice devuelve todos los elementos XML en todos los documentos de una BD con este nombre. ndices de atributos. Dado un nombre de atributo y un valor, este ndice devuelve todos los elementos que tienen un atributo con este nombre y valor. Hay tres tipos de ndices de atributos, de acuerdo con el tipo del valor del atributo: texto, numricos y de fecha / hora. o Texto. Por defecto, todos los valores de los atributos estn indexados como cadenas o texto. o Numrico. Si el valor se puede convertir al tipo double, entonces se aade como ndice atributo numrico. o Fecha/Hora. Si el valor se puede convertir al tipo date-time, entonces se aade como ndice date/time. ndices de contenido simple. Dado un nombre de elemento y un valor, este ndice devuelve todos los elementos que tienen un contenido simple correspondiente a este valor. ndices Full-text. Dada una palabra, este ndice devuelve todos los nodos de texto que contienen una ocurrencia de esta palabra. 6.1.- Especificaciones de indexado. Una especificacin de indexado es un documento XML con las siguiente estructura: El elemento raz tiene el nombre indexing. El elemento indexing contiene los atributos que definen las condiciones generales. Contiene una lista de reglas aplicables a los elementos o atributos. Ejemplo de xml de endexacion: <indexing xmlns:t="http://www.qizx.com/namespace/Tutorial"> <!-- Default rules --> <element as="numeric+string"/> <element as="date+string" /> <element as="string" /> <attribute as="numeric+string" /> <attribute as="date+string" /> <attribute as="string" /> <!-- Custom rules --> <element name="t:birthDate" context="t:author" as="date" sieve="com.qizx.api.util.text.FormatDateSieve" format="MMMM d, yyyy" locale="en-US" timezone="GMT" /> <element name="t:publicationDate" context="t:book" as="numeric" sieve="reindex.RomanNumberSieve" /> </indexing>

6.2.- Re-Indexar una BD desde Java. Para reindexar una BD XML de Qizx ser necesario un objeto de la clase
com.qizx.api.Indexing. Cada objeto Indexing es una especificacin de indexado con las reglas y parmetros necesarios para construir ndices en una BD o Library. El mtodo Indexing.parse(InputSource source) analiza la especificacin de indexado contenida en el texto XML del parmetro source. Adems se necesitan los siguientes mtodos de Library: Library.setIndexing(Indexing ind). Define las reglas de indexado para esa BD o Library, especificadas en el parmetro ind. Normalmente va seguida de un reindexado, que se realiza mediante el mtodo reIndex(). Library.reIndex(). Reconstruye y reorganiza los ndices de una BD package reindex; } finally { shutdown(lib, libManager); import java.io.IOException; } import java.io.File; } import org.xml.sax.SAXException; import org.xml.sax.InputSource; private static void usage() { import com.qizx.api.QizxException; System.err.println( import com.qizx.api.Indexing; "usage: java ReIndex libraries_storage_dir library_name" + import com.qizx.api.Library; " indexing_spec\n" + import com.qizx.api.LibraryManager; " libraries_storage_dir Directory containing libraries.\n" + import com.qizx.api.LibraryManagerFactory; " library_name Name of library being queried.\n" + " indexing_spec File containing the indexing specification."); public class ReIndex { System.exit(1); public static void main(String[] args) } throws IOException, SAXException, QizxException { if (args.length != 3) { private static Indexing loadIndexing(File file) usage(); throws IOException, SAXException, QizxException { } Indexing indexing = new Indexing(); File storageDir = new File(args[0]); String libName = args[1]; String systemId = file.toURI().toASCIIString(); File indexingFile = new File(args[2]); indexing.parse(new InputSource(systemId)); LibraryManagerFactory factory = LibraryManagerFactory.getInstance(); LibraryManager libManager = factory.openLibraryGroup(storageDir); Library lib = libManager.openLibrary(libName); try { verbose("Loading indexing specifications from '" + indexingFile + "'..."); Indexing indexing = loadIndexing(indexingFile); lib.setIndexing(indexing); verbose ("Re-indexing library '" + libName + "'..."); lib.reIndex(); return indexing; } private static void shutdown(Library lib, LibraryManager libManager) throws QizxException { lib.close(); libManager.closeAllLibraries(10000 /*ms*/); } private static void verbose(String message) { System.out.println(message); } }

7.- Gestin de transacciones. 7.1.- Los mtodos commit() y rollback().


Los mtodos para gestionar transacciones en Qizx los proporciona la interface Library y son: commit(). Confirma la transaccin actual. Si este mtodo se completa sin errores, las actualizaciones realizadas en la transaccin garantizan la persistencia, y se hacen visibles a otras sesiones. rollback(). Cancela la transaccin actual. En Qizx, todas las operaciones de actualizacin sobre una BD o Library, para que tengan efecto permanente, deben ir seguidas de una confirmacin o commit(). Por ejemplo, despus de realizar una consulta de actualizacin, para que permanezcan los cambios es necesario realizar un commit(), tal y como refleja el siguiente cdigo. private static void evaluaExpression(Expression expr, Library library) throws QizxException { /*ItemSequence results =*/ ItemSequence evaluate = expr.evaluate(); // confirmar cambios en BD library.commit(); } Por otra parte, al cerrar una conexin a una BD es necesario comprobar si hay alguna transaccin en curso, de manera que, si hay alguna en curso, para poder cerrar la BD habr que cancelar la transaccin actual. El cdigo que refleja de forma clara este hecho es el siguiente: //Si la base de datos esta inmersa en una transaccion if (bd.isModified()) { //deshace los cambios realizados por la transaccion bd.rollback(); } //cierra la conexion a la base de datos bd bd.close(); 8.- Tratamiento de excepciones. En Qizx, la clase que contiene los diferentes tipos de excecpiones es QizxException del paquete com.qizx.api. Esta clase extiende a Exception, superclase de todas las excepciones del API y sus constructores son: QizxException(String message). Construye un mensaje con la razn o causa de excepcin. El cdigo del error es indefinido. QizxException(String message, Throwable cause). Construye un mensaje con la razn o causa de excepcin, y la excepcin. El cdigo del error es indefinido. QizxException(QName errorCode, String message). Construye un mensaje con la razn de la excepcin y un cdigo de error XQuery. private static void cerrar(Library bd, LibraryManager bdManager) throws QizxException { bd.close();

bdManager.closeAllLibraries(10000 /*ms*/); } Tres subclases directas de QizxExcepction son: CompilationException. Excepciones debidas a errores en la compilacin de consultas a la BD. DataModelException. Excepciones debidas a manipulacin de documentos XML en la BD. EvaluationException. Excepciones debidas a errores en la ejecucin de una consulta. 8.1.- Excepciones en el procesamiento de consultas. Estas excepciones las puedes gestionar mediante dos subclases directas de la clase QizxException: CompilationException. Se lanza cuando hay errores de compilacin en una expresin de consulta. Los mensajes asociados pueden ser: el error, una advertencia o warning, y la descripcin o detalle del error. Podemos gestionar esos errores mediante los siguientes mtodos o getErrorCount() devuelve el nmero actual de errores. o getMessages() devuelve una lista de errores o warnings EvaluationException. Se lanza cuando hay errores en la ejecucin de una expresin XQuery. Por ejemplo, el siguiente cdigo muestra un mtodo que compila una expresin de consulta y controla posibles errores, almacenando en un array de tipo Message los posibles errores de compilacin, Observa que en este caso, el tratamiento de la excepcin se realiza mediante un bloque trycatch, y que en caso de que se produzca se captura la lista de errores. //Metodo para compilar la consulta controlando errores private static Expression compileExpression(Library bd, String consultaXquery) throws IOException, QizxException { Expression expr; try { expr = bd.compileExpression(consultaXquery); } catch (CompilationException e) { //mensajes de error devueltos tras la compilacion Message[] messages = e.getMessages(); for (int i = 0; i < messages.length; ++i) { System.out.println(messages[i].toString()); } throw e; } //devuelve consulta compilada return expr; } Otro Ejemplo package photoassociation; public void doGet(HttpServletRequest import java.io.*; httpservletrequest,HttpServletResponse httpservletresponse) import java.net.MalformedURLException; throws IOException { import java.net.URL; doPost(httpservletrequest, httpservletresponse); import javax.servlet.*; } import javax.servlet.http.*; import com.qizx.api.CompilationException; public void doPost(HttpServletRequest httpservletrequest, import com.qizx.api.Configuration; HttpServletResponse httpservletresponse) throws IOException { import com.qizx.api.Expression; httpservletresponse.setContentType("text/xml; import com.qizx.api.Item; UTF-8"); import com.qizx.api.ItemSequence; PrintStream out = new import com.qizx.api.Library; PrintStream(httpservletresponse.getOutputStream()); import com.qizx.api.LibraryManager; XQuerySessionManager manager = null; import com.qizx.api.LibraryManagerFactory; XQuerySession session = null; import com.qizx.api.LibraryMember; String date = import com.qizx.api.Message; httpservletrequest.getParameter("date"); import com.qizx.api.Node; String text = import com.qizx.api.QName; httpservletrequest.getParameter("text"); import com.qizx.api.QizxException; try { import com.qizx.api.XQuerySession; import com.qizx.api.XQuerySessionManager; Configuration.set(Configuration.ALLOWED_CLASSES, import com.qizx.api.util.DefaultModuleResolver; import com.qizx.api.util.XMLSerializer; "java.io.StringReader," + "java.io.StringWriter," public class XQueryServlet extends HttpServlet { + "java.io.Reader," + private static final long serialVersionUID = "java.net.URL," + 9186875057311859285L; "java.util.Map," + "java.util.List," + { "java.util.HashMap," + "java.lang.String," + System.setProperty("javax.xml.parsers.DocumentBuilderF actory", "photoassociation.qizx.UtilityFunctions,"+ "java.lang.Math"); "org.apache.xerces.jaxp.DocumentBuilderFactoryImpl"); manager = System.setProperty("javax.xml.parsers.SAXParserFactory" Configuration.createSessionManager("http://aphoteg.googlecode.co , m/hg/src/xquery/"); "org.apache.xerces.jaxp.SAXParserFactoryImpl"); manager.setModuleResolver(new } MyModuleResolver()); session = manager.createSession(); public void init(ServletConfig servletconfig) throws ServletException { session.getContext().declarePrefix("flickr", super.init(servletconfig); "http://www.flickr.com/services/api/"); }

session.getContext().declarePrefix("geoplanet", "http://developer.yahoo.com/geo/");

session.getContext().declarePrefix("photoAssociation", "http://web.tagus.ist.utl.pt/~rui.candeias/"); BufferedReader input = new BufferedReader(new out.println(m.getLineNumber() + ":" + InputStreamReader(this.getServletContext().getResourceAsStream(" m.getColumnNumber() + " -> " + m.getText()); /WEB-INF/classes/xquery/xquery2compile.xq"))); out.println(); String line = null; out.flush(); StringBuffer sBuffer = new } StringBuffer(); } while ( (line = input.readLine()) != null ) { sBuffer.append(line); sBuffer.append("\n"); } if (session != null && manager != null && String xqy = sBuffer.toString(); manager instanceof LibraryManager) try { shutdown( (Library)session, QName[] varNames = { (LibraryManager)manager); session.getQName("text") , session.getQName("date") }; } catch (Exception e2) { } String[] varValues = { text , date }; ex.printStackTrace(out); Expression expr = out.println("</error>\n </results>"); session.compileExpression(xqy); out.flush(); for (int i = 0; varNames != null && i < } varNames.length; ++i) { } expr.bindVariable(varNames[i], varValues[i], null); private static void shutdown(Library lib, LibraryManager } libManager) throws QizxException { ItemSequence results = expr.evaluate(); lib.close(); XMLSerializer serializer = new libManager.closeAllLibraries(10000); XMLSerializer(out, "UTF-8"); } serializer.setIndent(2); serializer.setOmitXMLDeclaration(true); class MyModuleResolver extends DefaultModuleResolver { out.println("<?xml version='1.0' encoding='UTF-8'?>"); public MyModuleResolver ( ) throws out.println("<results>"); MalformedURLException { while (results.moveToNextItem()) try { super ( new URL( Item result = "http://aphoteg.googlecode.com/hg/src/xquery/" ) ); results.getCurrentItem(); }; if (!result.isNode()) { out.println( "<error>" + result.getString() + "</error>" ); } public URL[] resolve (String Node node = result.getNode(); moduleNamespaceURI, String[] locationHints) throws serializer.reset(); MalformedURLException { String xmlForm = if serializer.serializeToString(node); (moduleNamespaceURI.equals("http://www.flickr.com/services/api/") out.println(xmlForm); ) out.flush(); return new URL[]{ new } catch ( Exception ex ) { URL("http://aphoteg.googlecode.com/hg/src/xquery/flickr.xqy") }; out.println("<error>"); else if if (session != null && manager (moduleNamespaceURI.equals("http://developer.yahoo.com/geo/")) != null && manager instanceof LibraryManager) try { return new URL[]{ new shutdown( URL("http://aphoteg.googlecode.com/hg/src/xquery/geoplanet.xqy") (Library)session, (LibraryManager)manager); }; } catch (Exception e2) { } else if ex.printStackTrace(out); (moduleNamespaceURI.equals("http://web.tagus.ist.utl.pt/~rui.cande out.println("</error>"); ias/")) out.flush(); return new URL[]{ new return; URL("http://aphoteg.googlecode.com/hg/src/xquery/photoAssociatio } n.xqy") }; out.println("</results>"); else return out.flush(); super.resolve(moduleNamespaceURI,locationHints); if (session != null && manager != null && } manager instanceof LibraryManager) { } shutdown( (Library)session, (LibraryManager)manager); } }

} catch (Exception ex) { out.println("<results>\n <error>"); if ( ex instanceof com.qizx.api.CompilationException) { for ( com.qizx.api.Message m : ((com.qizx.api.CompilationException)ex).getMessages() ) {

Você também pode gostar