Comience a usar DB2 9 pureXML ya mismo, Parte 5: Desarrolle aplicaciones Java para datos XML en DB2

IBM DB2 9 para Linux, UNIX, y Windows presenta un nuevo soporte significativo para el almacenamiento, la gestión y las consultas de datos XML. En este artículo, usted aprenderá los conceptos básicos relacionados con la escritura de aplicaciones Java con acceso a los nuevos datos XML. Usted verá cómo se insertan, consultan, actualizan y eliminan los datos XML, cómo se crean los procedimientos almacenados con acceso a los datos XML, y más.

Nota: Este artículo ha sido actualizado para incluir los cambios realizados en DB2 para Linux, UNIX y Windows 9.5 y 9.7.

Cynthia M. Saracco, Senior Software Engineer, EMC

Cindy Saracco photoC. M. Saracco trabaja en el Silicon Valley Laboratory de IBM, en la organización DB2 XML. Se ocupa de la gestión de bases de datos, XML, el desarrollo de aplicaciones Web y otros temas relacionados.



05-05-2010 (Primera publicación 05-05-2010)

La escritura de las aplicaciones Java con acceso a datos XML almacenados originalmente en DB2 9 no difiere demasiado de la escritura de las aplicaciones Java que acceden a datos relacionales. De hecho, si usted está familiarizado con Java Database Connectivity (JDBC), ya conoce muchos de los conceptos necesarios para comenzar a escribir su primera aplicación XML en DB2.

En este artículo, recorreremos diversos escenarios comunes de programación, como por ejemplo la inserción de datos XML, las consultas a datos que sean XML o no, la actualización de datos XML, la eliminación de datos XML, y la creación de procedimientos almacenados con acceso a datos XML. Pero en primer lugar, sugiero repasar algunos lineamientos fundamentales para el desarrollo de cualquier tipo de aplicación para bases de datos DB2.

Siga las típicas “mejores prácticas” de programación

Si bien el soporte a XML original de DB2 es nuevo, las buenas prácticas de programación de aplicaciones para bases de datos no han cambiado. Antes de ir de lleno a los detalles de la tecnología XML en DB2, recuerde estos principios generales:

  • Pida sólo lo que necesita: No recupere la totalidad del contenido de una tabla –ni la totalidad de los contenidos de muchos documentos XML– si solamente necesita un subconjunto de esta información. Lo único que logrará es incrementar los costos de procesamiento y demorar el rendimiento del tiempo de ejecución.
  • Evite duplicar el trabajo de un servidor de bases de datos: Indique a DB2 que filtre y procese los datos de acuerdo con sus necesidades, en lugar de hacerlo en su aplicación. Por ejemplo, si cuenta con resultados de una devolución de DB2 en un orden específico, usted no tendrá la necesidad de ordenar los datos. De modo similar, si usted hace que DB2 se asegure de que sólo se devuelvan resultados definidos, no tendrá necesidad de volver a revisarlos en busca de duplicados. El procesamiento centrado en datos es una tarea realizada de mejor manera por el servidor de bases de datos y no por su aplicación.
  • Haga que su código sea sencillo de actualizar: Incluya comentarios o Javadoc en su código, en especial si su aplicación contiene consultas complejas.
  • Considere cuidadosamente el alcance de sus transacciones: De manera predeterminada, JDBC trata a cada consulta como una transacción independiente. Determine si esto resulta adecuado a sus necesidades, y tome en cuenta de qué manera puede impactar el alcance (y el nivel de aislamiento) que usted define para sus transacciones sobre los requerimientos generales de concurrencia.
  • Minimice el tráfico en los entornos de red: Usted obtendrá un mejor rendimiento de los tiempos de ejecución si evita la transferencia innecesaria de datos entre su aplicación y DB2. La recuperación de solamente los datos que usted necesita es una de las maneras de hacerlo. También puede ser de ayuda invocar a los procedimientos almacenados en la base de datos, según la naturaleza de su trabajo.

Configure su entorno

DB2 no requiere una configuración especial para permitirle el desarrollo o la ejecución de aplicaciones Java que funcionan con datos XML. De hecho, usted puede escribir, verificar y depurar sus programas Java con el entorno de desarrollo integrado (integrated development environment - IDE) que elija o trabajando directamente con un Java Developer Kit (JDK) compatible desde la línea de comandos. Los ejemplos de este artículo usan IBM Data Studio (u Optim Development Studio) para su entorno de desarrollo. Esta sección se ocupa de la manera de configurar Data Studio, revisa algunos datos de muestra y explora los parámetros de configuración de las bases de datos que puedan serle de interés.

IBM Data Studio

IBM Data Studio se basa eb la plataforma Eclipse 3.4, un proyecto de código abierto que se encuentra disponible para su descarga. A fin de compilar y ejecutar una aplicación XML en DB2 con este banco de trabajo, usted deberá crear un proyecto e incluir las bibliotecas de DB2 adecuadas en la ruta de construcción del proyecto, incluyendo las bibliotecas que soportan el driver compatible con JDBC 4.0 de DB2. Para configurar su entorno, complete los siguientes pasos:

  1. Ponga en marcha Data Studio.
  2. Cree un nuevo proyecto. Inicialmente, usaremos un proyecto simple. Elija la perspectiva Java (Window > Open Perspective > Java (Ventana >Abrir perspectiva > Java)), y seleccione File (Archivo) >New (Nuevo)> Java Project (Proyecto Java). Siga las indicaciones de los asistentes para especificar el nombre del proyecto. Para los demás puntos, mantenga las configuraciones predeterminadas.
  3. Agregue las bibliotecas de DB2 a la ruta de construcción de su proyecto. Resalte su proyecto, haga clic en él con el botón derecho del mouse, y seleccioneProperties (Propiedades). Seleccione Java Build Path (Ruta de construcción Java), y haga clic en la pestaña Libraries (Bibliotecas). Agregue los archivos externos ,jar de DB2, como por ejemplo db2jcc.jar, db2jcc_javax.jar, y db2jcc_license_cu.jar.
  4. Alternativamente, cree un paquete para su aplicación. Resalte su proyecto, haga clic en él con el botón derecho del mouse y seleccione New > Package. (Nuevo > Paquete.)

Para ver más detalles sobre la creación de proyectos y paquetes, consulte la información presente en la ayuda online.

Datos de muestra

Los ejemplos de este artículo funcionan con la tabla "clients" creada en “Comience a usar DB2 9 ya mismo, Parte 2” (developerWorks, marzo de 2006). A modo de revisión rápida, esta tabla se definió como:

Listado1. Listado de código de muestra con su máxima amplitud
create table clients(
  id    		int primary key not null, 
  name  		varchar(50), 
  status 		varchar(10), 
  contactinfo 	xml
)

El Listado 2 muestra un archivo XML de muestra que en breve se insertará en la columna "contactinfo" de esta tabla.

Listado 2. Archivo XML de muestra a insertarse en la tabla "clients"
<?xml version="1.0"?>
<Client>
	<Address>
		<street>54 Moorpark Ave.</street>
		<city>San Jose</city>
		<state>CA</state>
		<zip>95110</zip>
	</Address>
	<phone>
		<work>4084630110</work>
		<home>4081114444</home>
		<cell>4082223333</cell>
	</phone>
	<fax>4087776688</fax>
	<email>sailer555@yahoo.com</email>
</Client>

Parámetros de configuración de la base de datos

Los ejemplos de este tutorial son simples y funcionan con una pequeña cantidad de datos XML, de manera que usted no deberá alterar los parámetros de configuración predeterminados para la base de datos para hacer que los mismos funcionen. Sin embargo, los valores predeterminados pueden no ser suficientes para algunos entornos de producción. Particularmente, puede ser necesario aumentar las configuraciones del tamaño del registro, el montículo Java, el montículo de enunciados de consulta, y el montículo de aplicaciones. Si estos valores no están configurados correctamente, el rendimiento de su tiempo de ejecución puede disminuir o es probable que usted no pueda insertar documentos XML de gran tamaño en las tablas de DB2 debido a espacio de registro insuficiente.

Usted puede revisar y modificar los parámetros de configuración de la base de datos desde el Control Center de DB2 (seleccione Tools > Configuration Assistant (Herramientas > Asistente de configuración)) o el procesador de la línea de comandos de DB2. Para más detalles, consulte el manual del producto.

Conéctese a su base de datos

El trabajo con datos XML en DB2 requiere el establecimiento de una conexión con la base de datos que contiene sus datos. Este código no presenta nada en especial, ya que sigue la misma lógica que usted escribiría si se conectara a cualquier base de datos de DB2.

El Listado 3 incluye una clase auxiliar con métodos para establecer y cerrar una conexión a base de datos de DB2.

Listado 3. Clase auxiliar para adquirir y liberar conexiones a bases de datos
public class Conn {
  // for simplicity, I've hard-coded account and URL data.
  private static String user = "user1";
  private static String pwd = "mypassword";
  private static String url = "jdbc:db2:test";

  // this method gets a database connection 	
  public static Connection getConn(){
    Connection conn=null;
		
    //  load the appropriate DB2 driver and 
    //  get a connection to the "test" database  
    try {
       Class.forName("com.ibm.db2.jcc.DB2Driver");
       conn = DriverManager.getConnection(url, user, pwd);
       . . . 	
    }
    catch (Exception e) { e.printStackTrace();	}
    return conn;
		
  }   // end getConn();
	
  // this method closes a database connection 
  public static void closeConn(Connection conn){
    try {
      if(conn == null) { return; }
      conn.close();
    }
    catch (Exception e) { e.printStackTrace(); }
    finally { 
      try { conn.close();  }
      catch (Exception e) { } 
    }
  }  // end closeConn();
}  // end class

Usted llamará a estos métodos en aplicaciones que realizan tareas más amplias, como por ejemplo, insertar y consultar datos XML.

Insertar datos XML

Debido a que la especificación XQuery inicial no se ocupaba de operaciones de escritura en bases de datos (como por ejemplo, insertar datos), DB2 depende de los populares enunciados SQLINSERTpara permitir a los programadores escribir nuevos datos XML en tablas que contienen columnas XML. DB2 puede almacenar cualquier documento XML bien formado de hasta 2 GB.

A menudo, los programadores de Java deben insertar datos XML incluidos en archivos en DB2, aunque también es posible insertar datos XML desde cadenas de caracteres, datos binarios (incluyendo grandes objetos) y enunciados SQL de sub-selección. El presente artículo incluye una revisión de cómo se insertan datos XML desde archivos y desde cadenas simples de caracteres. Consulte los manuales de CB2 9 para ver detalles de otros escenarios de inserción.

DB2 9 también le permite insertar documentos XML validándolos o no en función de esquemas XML previamente registrados. Las muestras de este artículo cubren ambos enfoques.

Inserción de archivo sin validación

El métodoinsertFile()del Listado 4 ilustra cómo se insertan datos de un archivo XML en la columna "clients.contactinfo". Este método comienza con la definición de diversas variables para su uso posterior. Las primeras tres corresponden a las columnas ID, name (nombre) y status (estado) de la tabla “clients". La cuarta es el nombre del archivo XML que se insertará en la columna "contactinfo". Por una cuestión de sencillez, los valores son inamovibles en este método; en un entorno de producción, los valores de entrada se obtendrían de manera diferente.

Después de establecer una conexión con la base de datos, cree una cadena simple para su enunciado INSERT. Como puede ver, su apariencia es similar a la de cualquier otro enunciado INSERT de DB2 y usa marcadores de parámetros para los cuatro valores de sus columnas de valores de entrada. El enunciado INSERT se prepara de la manera usual, y se establecen sus cuatro marcadores de parámetros. Para fijar el marcador para la columna XML, abra un FileInputStream, que pase por la ubicación de nuestro archivo XML. Además, deberá obtener la extensión de este archivo y usar esta información como datos de entrada para el método setBinaryStream(). Por último, ejecute el enunciado, verifique si hay errores y cierre la conexión.

Listado 4. Inserción de datos XML desde un archivo
public static void insertFile(){
  try {
    // for simplicity, I've defined variables with input data 
    int id = 1885;
    String name = "Amy Liu";
    String status = "Silver";
    String fn = "c:/XMLFiles/Client1885.xml";  // input file

    // get a connection 
    Connection conn = Conn.getConn();

    //   define string that will insert file without validation
String query = "insert into clients (id, name, status, contactinfo) values (?, ?, ? ,?)"0;

    // prepare the statement
    PreparedStatement insertStmt = conn.prepareStatement(query);
    insertStmt.setInt(1, id);
    insertStmt.setString(2, name);
    insertStmt.setString(3, status);
    File file = new File(fn);
    insertStmt.setBinaryStream(4, new FileInputStream(file), (int)file.length());

    // execute the statement 
    if (insertStmt.executeUpdate() != 1) {
        System.out.println("No record inserted.");
    }
    . . . 
    conn.close();
  }
  catch (Exception e) { . . . }
}

Insertar archivo con validación

La inserción de un archivo XML con validación requiere muy poco esfuerzo de programación adicional. Suponiendo que usted ha creado y registrado el archivo ClientInfo.xsd como se explicara en "Comience a usa DB2 9 ya mismo, Parte 2"(developerWorks, marzo de 2006), sólo deberá modificar un línea de código en el Listado 4 para indicarle a DB2 que inserte el archivo XML con validación. Este código involucra la definición de la cadena de query.

Como se muestra en el Listado 5, el enunciado INSERT revisado invoca a la función XMLValidate antes de especificar el marcador de parámetro para los datos XML. Esta función requiere también que usted especifique el identificador de esquemas XML que se usará en la validación. Aquí, se hace referencia a un esquema registrado previamente conocido como "user1.mysample".

Listado 5. Inserción de datos XML desde un archivo con validación
String query = "INSERT INTO clients (id, name, status contactinfo) " +
    "VALUES (?, ?, ?, xmlvalidate(? according to xmlschema id user1.mysample))";

Si su archivo XML de entrada contiene datos que son válidos de acuerdo con el esquema especificado, DB2 inserta la fila. De lo contrario, fracasa el enunciado completo, y no se insertan datos para esta fila.

Insertar cadena de caracteres sin validación

El método insertString() que se muestra en el Listado 5ilustra de qué manera usted puede insertar un documento XML bien formado asignado a una variable de cadena de caracteres en DB2. La lógica no difiere demasiado del ejemplo anterior de inserción de datos desde un archivo. En lugar de usar el método setBinaryStream()de su enunciado preparado, use el método setString(). Por cuestiones de sencillez, el documento XML de la definición de la variable xml es inamovible y predeterminada en este ejemplo.

Nota:Se incluyen caracteres de escape (barra oblicua invertida) antes de las comillas que forman parte del documento XML (como por ejemplo el número de versión de XML en el ejemplo que aparece a continuación).

Listado 6. Inserción de datos XML desde una cadena de caracteres
public static void insertString(){
  try {
    // for simplicity, I've defined variables with input data 
    int id = 1885;
    String name = "Amy Liu";
    String status = "Silver";
    String xml = 
      "<?xml version=\"1.0\"?>" + 
      "<Client>" + 
      "<Address> " +
        "<street>54 Moorpark Ave.</street>" +
        "<city>San Jose</city>" +
        "<state>CA</state>" +
        "<zip>95110</zip>" +
      "</Address>" +
      "<phone>" +
        "<work>4084630110</work>" +
        "<home>4081114444</home>" +
        "<cell>4082223333</cell>" +
      "</phone>" +
      "<fax>4087776688</fax>" +
      "<email>sailer555@yahoo.com</email>" +
      "</Client>";

    // get a connection 
    Connection conn = Conn.getConn();

    //   define string that will insert file without validation
String query = "insert into clients (id, name, status, contactinfo) values (?, ?, ? ,?)";

    // prepare the statement
    PreparedStatement insertStmt = conn.prepareStatement(query);
    insertStmt.setInt(1, id);
    insertStmt.setString(2, name);
    insertStmt.setString(3, status);
    insertStmt.setString(4, xml); 

    // execute the statement 
    if (insertStmt.executeUpdate() != 1) {
        System.out.println("No record inserted.");
    }
    . . . 
    conn.close();
  }
  catch (Exception e) { . . . }
}

Insertar cadena de caracteres con validación

Como seguramente usted espera, la validación de los documentos XML que se proporcionan como cadenas de caracteres requiere muy poco esfuerzo de programación. De hecho, sólo se debe modificar una línea de código: la definición de la variable query. Usted simplemente debe modificar el enunciado INSERT para invocar la función XMLValidate, del mismo modo que lo hizo en el Listado 5.

A continuación presentamos el enunciado revisado:

Listado 7. Inserción de datos XML desde una cadena de caracteres con validación
String query = "INSERT INTO clients (id, name, status contactinfo) " +
    "VALUES (?, ?, ?, xmlvalidate(? according to xmlschema id user1.mysample))";

Consultar datos XML

Ahora que usted sabe cómo insertar datos XML en DB2 usando un programa Java, está preparado para consultar datos XML. Esta sección incluye varios ejemplos para examinar, comenzando con una tarea simple (tal como recuperar un documento XML completo) para pasar a tareas más complejas (como por ejemplo devolver partes de documentos XML en base a predicados de consultas relacionales y XML).

Si bien DB2 soporta SQL y XQuery como lenguajes de nivel máximo, XQuery no ofrece un medio para resolver marcadores de parámetros. En la práctica, esto significa que cualquiera de las XQueries de su aplicación que requiera más que predicados de consulta predeterminados e inamovibles deberá estar incluida en un enunciado SQL usando una función SQL/XML tal como XMLQuery o XMLExists."Comience a usar DB2 9 ya mismo, Parte 3: Consulta de datos XML en DB2 con SQL" (developerWorks, marzo de 2006) se ocupa de estas funciones con más detalle. Aquí, usted verá como se usan en un programa Java. Y, sólo por diversión, también verá cómo se incluye una XQuery con predicados de consulta predeterminados e inamovibles en una aplicación.

Recuperar documentos XML completos

Nuestro primer método basado en consultas es bastante simple. Sólo recupera toda la información de contacto para un cliente dado. Una consulta de esta naturaleza se puede expresar fácilmente en SQL. Por lo tanto, si usted está familiarizado con JDBC, deberá comprender este código con facilidad.

El método simpleQuery() del Listado 8 declara diversas variables y luego establece una conexión a la base de datos usando un método auxiliar definido en el Listado 2. La cadena de query contiene un enunciado SQL simple para seleccionar toda la información de contacto para un cliente específico. Después de ejecutar el enunciado, la aplicación imprime los resultados que se han alcanzado en una variable de cadena de caracteres (stringDoc).

Listado 8. Recuperación de documentos XML completos con SQL
import java.sql.*;
 . . . 
public static void simpleQuery() {
  PreparedStatement selectStmt = null;
  String query = null, stringDoc = null;
  ResultSet rs = null;
  int clientID = 1885;
		
  try{	
     // get a connection 
    Connection conn = Conn.getConn(); 
    
    // define, prepare, and execute the query
    // this will retrieve all XML data for a specific client 
    query = "select contactinfo from clients where id = " + clientID
    selectStmt = conn.prepareStatement(query);
    rs = selectStmt.executeQuery();

    // check for results 
    if (rs.next() == false) {
        System.out.println("Can't read document with id " + clientID);
    }

     // fetch XML data as a string and print the results 
    else {
         stringDoc = rs.getString(1);
         System.out.println(stringDoc);
      }
      . . . 
      conn.close(); 
    }
    catch (Exception e) { . . . }	    
}

Este programa imprime una única fila de datos que contienen toda la información de contactos en XML para el cliente especificado.

Si bien no se muestra aquí, también es posible usar XQuery para recuperar uno o más documentos XML completes, siempre y cuando usted no deba incorporar marcadores de parámetros en su XQuery. Posteriormente en este artículo, usted verá un extracto de Java que usa XQuery para recuperar datos XML.

Recuperar porciones de documentos XML

Una tarea de programación común involucra la recuperación de porciones de documentos XML. El código Java de este ejemplo recupera los nombres y direcciones de correo electrónico primarias de clientes con un estado "Silver." El nombre del cliente y la información de su estado se almacenan en columnas SQL VARCHAR, mientras que las direcciones de correo electrónico se incluyen en documentos XML de la columna "contactinfo".

Por razones de tiempo, he omitido el código anteriormente mostrado, incluyendo sólo aquellas líneas que son ahora diferentes.

Listado 9. Recuperación de datos relacionales y fragmentos de XML con SQL/XML
. . . 
String status = "Silver";
		
try{	
     // get a database connection
    . . . .
    // define, prepare, and execute a query that includes 
    // (1) a path expression that will return an XML element and  
    // (2) a parameter marker for a relational column value 
   String query = "SELECT name, xmlquery('$c/Client/email[1]' " + 
       " passing contactinfo as \"c\") " + 
       " from clients where status = ?";
   PreparedStatement selectStmt = conn.prepareStatement(query);
   selectStmt.setString(1, status);
   ResultSet rs = selectStmt.executeQuery();
   
   // iterate over and print the results 
   while(rs.next() ){
        System.out.println("Name: " + rs.getString(1) +
           "   Email:  " + rs.getString(2));
    }
    . . . 
   // release resources 
}  
catch (Exception e) { . . . }

Este código emite un enunciado SQL/XML que llama a la función XMLQuery. Proporciona una función de la ruta a esta función que hace que DB2 navegue al primer elemento "email" por debajo del elemento root "Client" de los documentos XML de destino. (Observe que la expresión de la ruta distingue entre mayúsculas y minúsculas.) La variable $c y la cláusula SQL FROM indican dónde se encuentran estos documentos de destino: en la columna “contactinfo" de la tabla "clients". La cláusula SQL WHERE restringe aún más los documentos XML de destino a aquellos que se encuentran sólo en filas en las cuales el “status” del cliente tiene un determinado valor ("Silver," en este método).

El resultado de este programa puede tener la siguiente apariencia:

Listado 10. Muestra del resultado de la aplicación anterior
Name: Lisa Hansen   Email:  

Name: Amy Liu   Email:  <email>sailer555@yahoo.com</email>
. . . .

En este resultado de muestra, no se devolvió ninguna información de correo electrónico para un cliente con las características solicitadas (Lisa Hansen) porque este elemento no existía en su documento XML "contactinfo".

Cómo filtrar predicados relacionales y XML

Los programas Java pueden además, indicar a DB2 que filtre los resultados de las consultas en base a condiciones que corresponden a datos XML y a datos que no sean XML. El siguiente ejemplo se construye a partir del anterior, devolviendo los nombres y direcciones de correo electrónico primarias de los clientes "Silver" que viven en San José, California. Esta única consulta proyecta datos desde columnas XML y no XML y también restringe los datos en base a los contenidos de ambos tipos de columnas (XML y no XML).

El extracto que aparece a continuación incluye solamente porciones de código que han cambiado respecto del ejemplo anterior. En este caso, el enunciado SELECT invoca ahora a XMLExists como parte de la cláusula WHEREpara restringir los resultados a clientes que viven en la ciudad y el estado especificados (definidos en las variables city (ciudad) y state (estado), respectivamente).

Listado 11. Filtrado de datos XML en base a valores de elementos XML
. . . 
String status = "Silver";
String state = "CA";
String city = "San Jose";
. . . 	
try{	
    . . . .
   String query = "SELECT name, xmlquery('$c/Client/email[1]' " + 
       " passing contactinfo as \"c\") " + 
       " from clients where status = ?" 
       " and xmlexists('$c/Client/Address[state=$state][city=$city]' " +
       " passing contactinfo as \"c\", " + 
       " cast(? as char(2)) as \"state\", " + 
       " cast(? as varchar(30)) as \"city\" )";
   PreparedStatement selectStmt = conn.prepareStatement(query);
   selectStmt.setString(1, status);
   selectStmt.setString(2, state); 
   selectStmt.setString(3, city); 
   . . . 
}

La mayor parte de la consulta deberá resultarle familiar, por lo cual esta sección se concentra en las cuatro líneas finales. La función XMLExists indica a DB2 que determine si un documento XML dado contiene una dirección de cliente que incluye una ciudad y un estado determinados. La cláusula PASSING especifica dónde se encuentran los documentos XML: en la columna "contactinfo". La función CAST es llamada dos veces para presentar los valores de los parámetros de entrada (para ciudad y estado) a los tipos de datos adecuados.

El resultado de este programa es similar al resultado que se muestra en el Listado 9, suponiendo que tanto Lisa Hansen como Amy Liu viven en San José, California.

Usar una XQuery como lenguaje de nivel superior

Si bien DB2 es totalmente compatible con XQuery como lenguaje de nivel superior, la especificación XQuery inicial no se ocupó de los marcadores de parámetros. En la práctica, esto restringe el uso de XQueries en las aplicaciones Java. Las secciones anteriores ilustraron de qué manera se puede incrustar XQueries en SQL (usando las funciones XMLQuery y XMLExists, por ejemplo) para incorporar marcadores de parámetros. Esta sección explora qué es lo que usted puede hacer con XQuery en sus aplicaciones Java.

El siguiente ejemplo contiene una XQuery similar a la presentada en "Póngase en marcha rápidamente con DB2 9, Parte 4: Consultar datos XML en DB2 con XQuery" (developerWorks, abril de 2006). Esta XQuery determina cuáles son los clientes que viven en San José, California. Para cada uno de esos clientes, construye un fragmento de XML que contiene una "emailList" que incluye todas las direcciones de correo electrónico para ese cliente. Por último, devuelve una secuencia de emailLists.

Listado12. Recuperación de fragmentos XML con XQuery
try{	
    // get a database connection 
    Connection conn = Conn.getConn();

   // define, prepare, and execute an XQuery (without SQL). 
   // note that we must hard-code query predicate values. 
   String query = "xquery for $y in db2-fn:xmlcolumn" + 
      "('CLIENTS.CONTACTINFO')/Client " +
      "where $y/Address/city=\"San Jose\" and $y/Address/state=\"CA\"  " +  
      "return <emailList> { $y/email } </emailList>";
    PreparedStatement selectStmt = conn.prepareStatement(query);
    ResultSet rs = selectStmt.executeQuery();
   
     // iterate over all items in the sequence and print results.
     while(rs.next() ){
         System.out.println(rs.getString(1)); 
      }

      // release all resources 
      . . .  
     // catch and handle any exceptions 
     . . . 
}

Vale la pena observar dos aspectos de esta consulta. En primer lugar, la cadena de la consulta comienza con la palabra clave "xquery." La misma indica a DB2 que use su analizador de XQueries para procesar la consulta. Usted debe realizar esta tarea cada vez que usa XQuery como lenguaje externo. En segundo lugar, la consulta se refiere a los nombres de tabla y columna en mayúsculas. XQuery es un lenguaje que distingue entre mayúsculas y minúsculas. Debido a que DB2 por lo general pasa los nombres de tablas y columnas a mayúsculast cuando escribe esta información en sus catálogos internos, la XQuery debe corresponder a esta información.

El Listado 13 ofrece una muestra del resultado de este programa. Debido a que se devuelve un artículo "emailList" por cliente que clasifica, un rápido escaneo de este resultado indica que hay cuatro clientes que reúnen las condiciones. El primero de estos registros contiene una dirección de correo electrónico. El segundo no contiene nada (quizás porque el cliente no brindó esta información); en consecuencia, su emailList está vacía. El tercer registro que reúne las condiciones indica que hay dos direcciones de correo electrónico en el registro de este cliente. El cuarto contiene una dirección de correo electrónico para el cliente.

Listado13. Muestra del resultado de la aplicación anterior
<emailList><email>newemail@someplace.com</email></emailList>

<emailList/>

<emailList><email>beatlesfan36@hotmail.com</email>
<email>lennonfan36@hotmail.com</email></emailList>

<emailList><email>sailer555@yahoo.com</email></emailList>

Quizás se pregunte por qué los nombres de cada uno de los clientes que reunieron las condiciones no están incluidos en nuestros resultados. La respuesta es simple: XQuery trabaja con datos XML, y los nombres de los clientes se almacenan en una columna SQL VARCHAR. Por lo tanto, si desea que el resultado incluya los nombres de los clientes que reúnen las condiciones así como sus direcciones de correo electrónico, usted deberá escribir una consulta que incluya SQL y XQuery.

Actualizar y eliminar datos XML

Para actualizar y eliminar los datos XML almacenados en DB2, use los enunciados SQL UPDATE y DELETE. Estos enunciados pueden incluir funciones SQL/XML que restringen las filas y columnas de destino en base a los valores de los elementos XML almacenados en las columnas XML. Por ejemplo, usted puede eliminar las filas que contienen información sobre los clientes que viven en un código postal específico o actualizar los datos XML (y que no sean XML) sólo para los clientes que viven en un estado determinado.

Debido a que la sintaxis para usar las funciones SQL/XML en los enunciados UPDATE y DELETE es la misma que para usarlos en los enunciados SELECT, no se repetirán aquí las muestras del código completo. En cambio, sólo se incluirán breves extractos. Consideremos en primer lugar las operacionesDELETE.

Ejemplos de eliminaciones

La eliminación de una fila que contiene datos XML es simple. Simplemente use el enunciado SQL DELETE con una cláusula WHERE(si lo desea) para restringir las filas a eliminar. Por ejemplo, el siguiente código elimina la fila para el cliente con ID 1885:

Listado14. Eliminación de datos en base a un valor de datos relacionales
. . . 
 int clientID = 1885;
String query = "delete FROM clients WHERE id = ?";
 . . .  
PreparedStatement stmt = conn.prepareStatement(query);
stmt.setInt(1, clientID);
if (stmt.executeUpdate() == 0) {
   System.out.println("No records deleted.");
}
else { System.out.println("Record(s) deleted."); }
 . . .

Si usted desea restringir sus operacionesDELETEen base a los valores de los elementos XML, simplemente invoque las funciones SQL/XML adecuadas en su cláusula WHERE. El Listado 14 usa la función XMLExists para especificar que se debería eliminar la información sobre todos los clientes que viven en Maine (abreviado "ME"):

Listado 15. Eliminación de datos en base a un valor de elemento XML
String state = "ME";
String query = "delete from clients " + 
" where xmlexists('$y/Client/Address[state=$state]' " +
" passing clients.contactinfo as \"y\", " + 
" cast(? as char(2)) as \"state\" )";
. . . 
PreparedStatement stmt = conn.prepareStatement(query);
stmt.setString(1, state);
. . .

Ejemplos de actualizaciones

Con DB2 9, usted puede actualizar datos en una columna XML usando el enunciado SQL UPDATE o un procedimiento almacenado, como por ejemplo,DB2XMLFUNCTIONS.XMLUPDATE. En ambos casos, las actualizaciones a la columna XML se producen al nivel del documento, en lugar de al nivel de un elemento. Sin embargo, los programadores que actualizan con el procedimiento almacenado no necesitan suministrar el documento XML completo a DB2. Sólo deben especificar los elementos XML a actualizar, y DB2 preserva los datos inalterados del documento al tiempo que actualiza los elementos especificados. Los programadores que emiten enunciados UPDATE deben especificar un documento completo (y no sólo los elementos que desean modificar).

Parte de la versión DB2 9.5, sin embargo, simplificó en gran medida los documentos XML existentes. En esta versión , implementamos una nueva función XQuery denominada "Transform". Esta función expandió el lenguaje inicial de XQuery para ir más allá de las simples consultas a XML, a las actualizaciones de XML.

El Listado 16 actualiza la información de contacto para el cliente con ID 1333 usando los datos XML contenidos en un archivo. Observe que los nuevos datos XML se validan respecto de un esquema registrado como parte de la operación de actualización:

Listado 16. Actualización de datos XML desde un archivo
int clientID = 1333;
String fn = "c:/XMLFiles/Client1333.xml";  // input file
String query = "update clients set contactinfo = " +
  "xmlvalidate(? according to xmlschema id user1.mysample) " + 
  "where id = ?";
. . . 
PreparedStatement stmt = conn.prepareStatement(query);
stmt.setInt(2, clientID);
File file = new File(fn);
stmt.setBinaryStream(1, new FileInputStream(file), (int)file.length());
. . .

Por supuesto, usted también puede usar un predicado de consulta XML para especificar el /los registro/ de contacto del cliente que desea actualizar. Nuevamente, debe usar funciones SQL/XML para hacerlo. Imagine que un cliente desea que usted actualice su número de fax pero no recuerda la propia ID de cliente. En cambio, le da su número de teléfono particular para ayudarlo a localizar su información. El siguiente extracto usa XMLExists para restringir las actualizaciones solamente al registro que contiene su número telefónico particular. Observe que toda la información de contacto del cliente se suministra como una cadena Java que contiene el documento XML revisado. Este es el método que se debe seguir con DB2 9.1. Sin embargo, con DB2 9.5, usted cuenta con la recientemente agregada función W3C denominada XML Transform o Update. Esta nueva función, ahora en estado de recomendación, le permite actualizar un nodo, eliminar un nodo, reemplazar un nodo o modificar un nodo. La función transform requiere una sintaxis especial, que se muestra en el Listado 17b. Con esta nueva función, usted básicamente toma una instantánea de un documento XML existente, realiza las modificaciones y luego lo reemplaza con los nuevos cambios. El Listado 17b muestra la diferencia con 9.5 y la nueva función Transform.

Listado17. Actualización de datos XML con una cadena de caracteres
String homeph = "4081114444";
String xml = 
   "<?xml version=\"1.0\"?>" +
   "<Client>" +
   "<Address> " +
      "<street>54 Moorpark Ave.</street>" +
      "<city>San Jose</city>" +
      "<state>CA</state>" +
      "<zip>95110</zip>" +
   "</Address>" +
   "<phone>" +
      "<work>4084630110</work>" +
      "<home>4081114444</home>" +
      "<cell>4082223333</cell>" +
   "</phone>" +
      "<fax>4087773111</fax>" +
   "<email>sailer555@yahoo.com</email>" +
   "</Client>";

String query =  "update clients set contactinfo = ?" + 
   "where xmlexists('$y/Client/phone[home=$homeph]' " +
   " passing clients.contactinfo as \"y\", " + 
   " cast(? as varchar(11)) as \"homeph\" )";
. . . 
PreparedStatement stmt = conn.prepareStatement(query);
stmt.setString(1, xml);
stmt.setString(2, homeph);
. . .
Listado 17b. Actualización de datos XML con una cadena de caracteres usando DB2 V9.5 y la función Transform de XQuery.
String homeph = "4081114444";
String xml =
         "4087773111";

String query =  "update clients  set contactinfo = " +
           "xmlquery('  "+
            "copy $new :=$CONTACTINFO" +
            "modify do replace value of $new/Client/fax with $p " +
            "return $new "+
             
         "passing cast (? as varchar(11)) as "p") "+
   "where xmlexists('$y/Client/phone[home=$homeph]') "  +
      "passing clients.contactinfo as \"y\"  ";

. . . 
PreparedStatement stmt = conn.prepareStatement(query);
stmt.setString(1, xml);
stmt.setString(2, homeph);
. . .

Generador de consultas

Si usted necesita ayuda con la escritura de las consultas de su aplicación, Developer Workbench le ofrece asistentes que generan consultas SQL/XML y XQueries. Debido a que la mayoría de los programadores de Java programan aplicaciones que requieren marcadores de parámetros, a menudo usan SQL/XML. Esta sección le muestra un breve ejemplo de cómo se usa el generador de consultas SQL para generar un enunciado SQL/XML similar al incluido en el Listado 9.

Para generar un enunciado SQL/XML, siga estos pasos:

  1. Prepare su espacio de trabajo.
  2. Especifique las características de su consulta.
  3. Ejecute la consulta.

Veamos cada uno de estos pasos por separado.

Prepare su espacio de trabajo

Los enunciados SQL son generados como parte de un Proyecto de Datos accesible desde la perspectiva Datos del banco de trabajo. Para crear dicho proyecto, complete los siguientes pasos:

  1. Abra la perspectiva Datos. Seleccione Window > Open Perspective > Other > Data. (Ventana > Abrir Perspectiva > Otros > Datos)
  2. Cree una conexión a su base de datos de destino.Con el botón derecho del mouse, haga clic dentro del recuadro Database Explorer ubicado en el extremo inferior izquierdo. Seleccione New Connection (Nueva conexión) y especifique el nombre de su base de datos, el nombre de usuario y la contraseña.
  3. Cree un nuevo Proyecto de Datos. Con el botón derecho del mouse, haga clic dentro del recuadro Data Project Explorer (Explorador de proyecto de datos) ubicado en el extremo superior izquierdo. Seleccione New > Project > Data > Data Development Project. (Nuevo > Proyecto > Datos > Proyecto de desarrollo de datos) Cuando se le solicite, otorgue un nombre al proyecto de su elección, y asócielo con la conexión a la base de datos que usted creó anteriormente.

Una vez abierta la conexión a la base de datos y creado el proyecto de datos, usted estará listo para generar las consultas.

Genere su consulta

Para mantener la sencillez de este tutorial, cree un enunciado SQL/XML que devuelva la dirección de correo electrónico primaria de los clientes que poseen un cierto estado. La consulta será similar a::

Listado 18. Muestra de consulta SQL/XML
SELECT name, xmlquery('$c/Client/email[1]'  
passing contactinfo as "c")   
from clients where status = ?

Siga estos pasos para generar su consulta:

  1. Inicie el SQL Builder. Dentro de su Data project, resalte la carpeta SQL Scripts y haga clic en ella con el botón derecho del mouse. Seleccione New > SQL Statement (Nuevo > Enunciado SQL). Cuando se le solicite, acepte los valores predeterminados para el nombre de su proyecto y especifique un nombre para su enunciado SQL. Acepte el tipo de enunciado predeterminado (SELECT) y elija usar el generador de SQL. Haga clic en Finish (Finalizar).
  2. Especifique la tabla a consultar. Con el botón derecho del mouse, haga clic en el recuadro central y seleccione Add Table. (Agregar tabla) Expanda su carpeta de esquemas y seleccione la tabla "clients".
  3. Especifique las columnas de su interés Para este ejemplo, usted debe incluir una columna y el resultado de una función (XMLQuery) en el conjunto de resultados. Para ello, complete los siguientes pasos:
    1. Marque la columna "names" que aparece en el recuadro central.
    2. Haga clic en la primera fila que se muestra en la pestaña Column debajo del recuadro central. Haga clic en el extremo derecho de esta celda para visualizar una tecla de dirección y seleccione Build Expression. (Generar expresión) Haga clic en Enter.
    3. Seleccione Function en el menú que aparece.
    4. Seleccione XML como categoría de la función y XMLQuery como función. A continuación del Parameter Value 1 (Valor de parámetro 1), haga clic en la flecha de la celda Value (Valor) y seleccione Edit Expression (Editar expresión).
    5. Especifique la expresión de la ruta adecuada en el String Constant Builder: $c/Client/email[1], y haga clic en Finish dos veces.
    6. Modifique el enunciado SQL generado para incluir una cláusula PASSING en la función XQuery. La función XQuery final deberá ser así: '$c/Client/email[1]' passing contactinfo as "c"
  4. Especifique el predicado de la consulta (cláusulaWHERE). Para este ejemplo, usted debe agregar un predicado de consulta para una columna relacional.
    1. En la pestaña Conditions ubicada debajo de su enunciado SQL/XML, haga clic en la primera fila que se muestra en la pestaña Column. Haga clic en la tecla de dirección que aparece en el extremo derecho de esta celda y seleccione la columna status.
    2. Haga clic en la celdaOperatory seleccione la igualdad de operador ("=").
    3. Haga clic en la tecla de dirección ubicada en el extremo derecho de la celda Value y seleccione Build Expression. Oprima Enter.
    4. Seleccione Constant y luego String Constant cuando se le solicite.
    5. Especifique un nombre para la variable de host a ingresar por el usuario (como por ejemplo "status"). Haga clic en Finish.

Ejecute su consulta

Después de generar su consulta, usted estará listo para ejecutarla.

  1. Ubique la consulta en su Proyecto de Datos, haga clic en ella con el botón derecho del mouse, y seleccione Run SQL.
  2. Cuando se le solicite, especifique un valor de entrada para el estado del cliente (como por ejemplo "Gold" o "Silver"), y haga clic en OK.
  3. Revise los resultados en el recuadro Data Output.

Procedimientos almacenados

En los entornos de red, los procedimientos almacenados a menudo reducen la comunicación necesaria entre una aplicación del cliente y DB2. Esto, por supuesto, mejora el rendimiento del tiempo de ejecución. Con DB2 9, los procedimientos almacenados pueden incluir parámetros y variables de XML.

Si bien la discusión detallada de los procedimientos almacenados no está incluida en el alcance de este artículo, se ofrece un repaso de la misma para un escenario simple de manera que usted pueda ver cómo se escribe un procedimiento almacenado en DB2 para recuperar porciones de documentos XML. Este escenario usa asistentes de Data Studio para generar, implantar y ejecutar el código del procedimiento almacenado en SQL que sea necesario. Si lo desea, usted puede desarrollar e implantar un procedimiento almacenado en SQL equivalente con el procesador de la línea de comandos de DB2. Además, usted puede escribir procedimientos almacenados basados en XML en Java.

Para este ejemplo, usted escribirá un procedimientos almacenado que recupera los nombres y direcciones de correo electrónico primarias de clientes con un cierto estado, al igual que hizo anteriormente. Si bien éste es un procedimiento bastante sencillo, lo ayudará a comprender cómo se generan los procedimientos basados en SQL que consultan y devuelven datos XML usando asistentes incorporados.

Para crear este procedimiento, siga estos sencillos pasos:

  1. Prepare su espacio de trabajo.
  2. Especifique los contenidos de su procedimiento.
  3. Implante y pruebe su procedimiento.

Analicemos ahora cada uno de ellos.

Prepare su espacio de trabajo

Los procedimientos almacenados se definen como parte de un proyecto de datos. Si aún no lo ha hecho, abra la perspectiva Data, establezca una conexión a la base de datos, y cree un proyecto de datos. Para más detalles, consulte la sección anterior Prepare su espacio de trabajo.

Cree su procedimiento

Nuestro procedimiento almacenado basado en SQL invoca a un único enunciado SQL/XML para consultar la tabla "clients" en base a lo ingresado por quien realiza la consulta. Este procedimiento devuelve un único resultado que contiene una columna SQL VARCHAR(para el nombre del cliente) y una columna XML (para el correo electrónico del cliente). La consulta será similar a:

Listado 19. Ejemplo de consulta SQL/XML
SELECT name, xmlquery('$c/Client/email[1]'  
passing contactinfo as "c")   
from clients where status = ?

El proceso para construir un procedimiento almacenado SQL con acceso a datos XML no difiere de la construcción de un procedimiento SQL con acceso a datos que no sean XML. A continuación presentamos una manera de hacerlo:

  1. Defina un nuevo procedimiento almacenado. Expanda su nuevo proyecto de datos; resalte Stored Procedures, y con el botón derecho del mouse haga clic en el mismo. Seleccione New > Stored Procedure. Siga los avisos para verificar el nombre del proyecto y especifique un nombre para el procedimiento almacenado. Mantenga el tipo de lenguaje predeterminado en SQL.
  2. Especifique su/s enunciado/s SQL. Cuando se le solicite, usted puede escribir su enunciado de consulta directamente o servirse de los asistentes para que lo ayuden a crear uno. Para esta última tarea, siga estos pasos
    1. Haga clic en Create SQL.
    2. Acepte el tipo de enunciado predeterminado (SELECT) y el proceso de desarrollo predeterminado (orientación por asistentes para la generación del enunciado).
    3. Seleccione la pestaña clients como el objetivo de su enunciado.
    4. En la pestaña Columns, incluya dos columnas en el conjunto final de resultados. Seleccione names, y luego Add > Function > Next. En la siguiente ventana, especifique la categoría de la función como XML, y la firma de la función como XMLQuery. Haga clic en Finish.
    5. En la pestaña Conditions, genere la cláusula SQL WHERE. Especifique clients.status como la columna, igual a("=")como el operador, e :input como el valor.
    6. Modifique el enunciado SQL resultante para que incluya la expresión de ruta correcta para recuperar la primera dirección de correo electrónico de la columna "contactinfo". Específicamente, modifique la línea XMLQUERY para que diga:xmlquery('$c/Client/email[1]' passing contactinfo as "c")
    7. Analice su consulta para verificar que no existan errores de sintaxis.
  3. Especifique la información de la implantación. En particular, puede resultarle útil para Activar Depuración.
  4. Alternativamente, revise el código SQL generado. Haga clic en Show SQL. (Mostrar SQL)(Consulte el Listado 20 para ver una muestra de lo que deberá visualizarse.)
  5. Complete el procedimiento almacenado. haga clic en Finish.
Listado 20. Muestra del código generado para el procedimiento almacenado en SQL relacionado con los datos XML
CREATE PROCEDURE foo (INPUT VARCHAR(10)
	DYNAMIC RESULT SETS 1
--------------------------------------------
--SQL Stored Procedure
	--INPUT
--------------------------------------------
P1:BEGIN
	--------------------------------------------
	--Variables declaration fragment inserted from SP_SQL_VAR.FRAGMENT
	--------------------------------------------

	--Declare cursor
	DECLARE cursor1 CURSOR WITH RETURN FOR
		SELECT NAME, XMLQUERY('$c/Client/email[1]' PASSING CONTACTINFO AS "c")
		 FROM CLIENTS
		 WHERE STATUS=INPUT;

	--Cursor left open for client application
	OPEN cursor1;
END P1

Implante y pruebe si procedimiento

Una vez creado su procedimiento, usted estará listo para implantarlo y probarlo. Siga estos pasos:

  1. Implante el procedimiento. Ubique el procedimiento en su Proyecto de Datos, haga clic en el mismo con el botón derecho del mouse, y seleccione Deploy. Acepte los valores predeterminados y haga clic en Finish. En el recuadro Data Output ubicado en el extremo inferior derecho se observará que su procedimiento se ha implantado con éxito.
  2. Ejecute el procedimiento. Ubique el procedimiento en su Proyecto de Datos, con el botón derecho del mouse haga clic en el mismo y seleccione Run. Cuando se le solicite, especifique un valor de entrada para el estado del cliente (como por ejemplo "Gold" o "Silver"). Haga clic e n OK, y visualice los resultados de su procedimiento almacenado en el recuadro Data Output.

Usted, si lo desea, puede llamar al procedimiento almacenado desde fuera de su Developer Workbench. Por ejemplo, si usted denominó a su procedimiento "getInfo," podría invocar al procesador de la línea de comandos de DB2, conectarse con la base de datos y emitir este enunciado:

Listado 21. Invocación del procedimiento almacenado
call getInfo('Silver')

Resumen

La escritura de aplicaciones Java que funcionan con datos DB2 XML involucra el uso de los famosos códigos JDBC para ejecutar consultas y procesar sus resultados. IBM ofrece herramientas tales como Data Studio, un banco de trabajo basado en Eclipse, que sirven para ayudarlo a codificar, verificar y depurar su trabajo. Junto con Data Studio vienen asistentes para la exploración de los contenidos de sus bases de datos, la escritura de procedimientos almacenados con acceso a datos XML y no XML, la escritura de XQueries con acceso a datos XML, y la escritura de enunciados SQL/XML con acceso a datos XML y no XML.

Agradecimientos

Gracias a Don Chamberlin, Grant Hutchison, y Brian Payton por su revision de este artículo.

Recursos

Aprender

Obtener los productos y tecnologías

  • Genere su próximo proyecto de desarrollo con el software de prueba de IBM, disponible para descargar directamente desde developerWorks.
  • Ahora usted puede usar DB2 sin costo alguno. Descargue DB2 Express-C, una versión gratuita de DB2 Express Edition para la comunidad que ofrece las mimas características de datos centrales que DB2 Express Edtion y brinda una sólida base para construir e implantar sus aplicaciones.

Comentar

Comentarios

developerWorks: Ingrese

Los campos obligatorios están marcados con un asterisco (*).


¿Necesita un IBM ID?
¿Olvidó su IBM ID?


¿Olvidó su Password?
Cambie su Password

Al hacer clic en Enviar, usted está de acuerdo con los términos y condiciones de developerWorks.

 


La primera vez que inicie sesión en developerWorks, se creará un perfil para usted. La información en su propio perfil (nombre, país/región y nombre de la empresa) se muestra al público y acompañará a cualquier contenido que publique, a menos que opte por la opción de ocultar el nombre de su empresa. Puede actualizar su cuenta de IBM en cualquier momento.

Toda la información enviada es segura.

Elija su nombre para mostrar



La primera vez que inicia sesión en developerWorks se crea un perfil para usted, teniendo que elegir un nombre para mostrar en el mismo. Este nombre acompañará el contenido que usted publique en developerWorks.

Por favor elija un nombre de 3 - 31 caracteres. Su nombre de usuario debe ser único en la comunidad developerWorks y debe ser distinto a su dirección de email por motivos de privacidad.

Los campos obligatorios están marcados con un asterisco (*).

(Por favor elija un nombre de 3 - 31 caracteres.)

Al hacer clic en Enviar, usted está de acuerdo con los términos y condiciones de developerWorks.

 


Toda la información enviada es segura.


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=90
Zone=Information mgmt, Rational
ArticleID=487564
ArticleTitle=Comience a usar DB2 9 pureXML ya mismo, Parte 5: Desarrolle aplicaciones Java para datos XML en DB2
publish-date=05052010