Tenha um início rápido com o DB2 9 pureXML, Parte 5: Desenvolva aplicativos Java para dados XML do DB2

O IBM DB2 9 para Linux, UNIX e Windows exibe recursos novos e significativos de suporte ao armazenamento, gerenciamento e consulta de dados XML. Neste artigo, você conhecerá os fundamentos da criação de aplicativos Java que acessam os novos dados XML. Você aprenderá a inserir, consultar, atualizar e excluir dados XML, a criar procedimentos armazenados que acessam dados XML e mais.

Observação: Este artigo foi atualizado para incluir as alterações no DB2 para Linux, UNIX e Windows, Versões 9.5 e 9.7.

Cynthia M. Saracco, Senior Software Engineer, IBM

Cindy Saracco photoC. M. Saracco trabalha com o Laboratório da IBM no Vale do Silício na organização de XML no DB2. Ela trabalha no gerenciamento de banco de dados, XML, desenvolvimento de aplicativo da Web e assuntos relacionados.



16/Abr/2010 (Primeira publicação 16/Abr/2010)

Escrever aplicativos Java que acessam dados XML armazenados nativamente no DB2 9 não é muito diferente de escrever aplicativos Java que acessam dados relacionais. De fato, se você está familiarizado com Java Database Connectivity (JDBC), já sabe boa parte do que é necessário para começar a escrever seu primeiro aplicativo XML para DB2.

Neste artigo, abordaremos passo a passo vários cenários comuns de programação, como a inserção de dados XML, a consulta de dados XML e não-XML, a atualização de dados XML, a exclusão de dados XML e a criação de procedimento armazenados que acessam dados XML. Antes, porém, revisaremos algumas diretrizes fundamentais para o desenvolvimento de qualquer tipo de aplicativo para banco de dados DB2.

Siga as "boas práticas" típicas de programação

Embora o suporte nativo a XML no DB2 seja novo, as boas práticas de programação de aplicativos para banco de dados não mudaram. Antes de mergulhar nos detalhes da tecnologia XML do DB2, lembre-se dos seguintes princípios gerais:

  • Solicite apenas aquilo de que você precisa: não recupere todo o conteúdo de uma tabela -- ou todo o conteúdo de muitos documentos XML -- se precisar somente de um subconjunto dessas informações. Isso aumentará o custo de processamento e reduzirá o desempenho em tempo de execução.
  • Evite duplicar o trabalho de um servidor de banco de dados: instrua o DB2 para filtrar e processar dados de acordo com suas necessidades, em vez de fazer esse trabalho no seu aplicativo. Por exemplo, se você determinar que o DB2 retorne os resultados em uma determinada ordem, não precisará classificar os dados por conta própria. Da mesma forma, se fizer o DB2 garantir que somente resultados distintos serão retornados, você não precisará verificar novamente se há duplicatas. O processamento centrado em dados funciona melhor quando é executado pelo servidor de banco de dados, não pelo seu aplicativo.
  • Crie código de fácil manutenção: inclua comentários ou Javadoc no código, particularmente se o seu aplicativo contiver consultas complexas.
  • Considere cuidadosamente o escopo de suas transações: por padrão, JDBC trata cada consulta como uma transação independente. Determine se isso é apropriado para as suas necessidades e considere também como o escopo (e o nível de isolamento) definido para as suas transações poderá afetar os requisitos globais de simultaneidade.
  • Minimize o tráfego em ambientes de rede: o desempenho em tempo de execução será melhor se você evitar a transferência desnecessária de dados entre o seu aplicativo e o DB2. Recuperar somente os dados necessários é uma maneira de fazer isso. Invocar procedimentos armazenados de banco de dados também pode ajudar, dependendo da natureza do trabalho.

Configure o seu ambiente

O DB2 não exige qualquer configuração especial para permitir o desenvolvimento ou a execução de aplicativos Java que trabalham com dados XML. De fato, é possível escrever, testar e depurar programas em Java usando o ambiente de desenvolvimento integrado (IDE) de sua escolha ou trabalhando diretamente com um Java Developer Kit (JDK) suportado a partir da linha de comando. Os exemplos deste artigo usam o IBM Data Studio (ou o Optim Development Studio) como ambiente de desenvolvimento. Esta seção discute como configurar o Data Studio, examina alguns dados de exemplo e explora os parâmetros de configuração de banco de dados que podem ser relevantes para você.

IBM Data Studio

O IBM Data Studio é baseado na plataforma Eclipse 3.4, um projeto de software livre disponível para download gratuito. Para compilar e executar qualquer aplicativo XML para DB2 com essa referência, é necessário criar um projeto e incluir no caminho de construção do projeto as bibliotecas DB2 apropriadas, inclusive as bibliotecas que suportam o driver compatível com JDBC 4.0 do DB2. Para configurar o seu ambiente, conclua as etapas a seguir:

  1. Inicie o Data Studio.
  2. Crie um novo projeto. Usaremos inicialmente um projeto simples. Mude para a perspectiva Java (Window > Open Perspective > Java) e selecione File > New > Java Project. Siga os assistentes para especificar o nome do projeto. Para os outros itens, mantenha as configurações padrão.
  3. Adicione as bibliotecas DB2 ao caminho de construção do projeto. Realce o seu projeto, clique com o botão direito do mouse e selecione Properties. Selecione Java Build Path e clique na guia Libraries. Adicione os arquivos .jar externos do DB2 apropriados, como db2jcc.jar, db2jcc_javax.jar e db2jcc_license_cu.jar.
  4. Opcionalmente, crie um pacote para o seu aplicativo. Realce o seu projeto, clique com o botão direito do mouse e selecione New > Package.

Para obter mais detalhes sobre a criação de projetos e pacotes, consulte as informações da ajuda on-line.

Dados de exemplo

Os exemplos neste artigo usam a tabela "clients" criada em "Get off to a fast start with DB2 9, Part 2 (developerWorks, março de 2006). Recapitulando rapidamente, essa tabela foi definida como:

Listagem 1. Listagem de código de exemplo com largura máxima
create table clients(
  id    		int primary key not null, 
  name  		varchar(50), 
  status 		varchar(10), 
  contactinfo 	xml
)

A Listagem 2 mostra um arquivo XML que será inserido a seguir na coluna "contactinfo" dessa tabela.

Listagem 2. Arquivo XML de exemplo a ser inserido na tabela "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 configuração de banco de dados

Como os exemplos deste tutorial são simples e utilizam uma pequena quantidade de dados XML, não é necessário alterar os parâmetros de configuração padrão do banco de dados para que eles possam ser executados. Entretanto, os valores padrão podem não ser suficientes para alguns ambientes de produção. Especificamente, talvez seja necessário aumentar o valor das configurações de tamanho do log, heap Java, heap de instruções de consulta e heap de aplicativo. Se esses valores foram definidos inadequadamente, o desempenho em tempo de execução poderá ser lento ou a inserção de documentos XML grandes em tabelas do DB2 poderá ser impossível devido ao espaço insuficiente em log.

Os parâmetros de configuração do banco de dados DB2 podem ser examinados e alterados a partir do DB2 Control Center (selecione Tools > Configuration Assistant) ou do processador de linha de comando do DB2. Consulte o manual do produto para obter mais detalhes.

Conectar ao banco de dados

Para trabalhar com dados XML do DB2, é necessário estabelecer uma conexão com o banco de dados que contém os dados. Não há nada de especial com esse código -- é a mesma lógica usada na conexão com qualquer banco de dados DB2.

A Listagem 3 contém uma classe auxiliar com métodos para estabelecer e encerrar uma conexão com um banco de dados DB2.

Listagem 3. Classe auxiliar para adquirir e liberar conexões de banco de dados
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
Listagem 4. Inserir dados XML de um arquivo
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 (?, ?, ? ,?)";
    // 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) { . . . }
}

Inserir arquivo com validação

A inserção de um arquivo XML com validação exige um mínimo de programação adicional. Presumindo que você tenha criado e registrado o arquivo ClientInfo.xsd como foi discutido em "Get off to a fast start with DB2 9, Part 2" (developerWorks, março de 2006), só é necessário modificar uma linha de código na Listagem 4 para instruir o DB2 a inserir o arquivo XML sem validação. Esse código é usado para definir a cadeia de caractere query.

Como é mostrado na Listagem 5, a instrução INSERT revisada invoca a função XMLValidate antes de especificar um marcador de parâmetro para os dados XML. Essa função também exige que você especifique o identificador do esquema XML a ser usado para validação. Aqui, é referenciado um esquema registrado anteriormente chamado "user1.mysample".

Listagem 5. Inserir dados XML de um arquivo sem validação
String query = "INSERT INTO clients (id, name, status contactinfo) " +
    "VALUES (?, ?, ?, xmlvalidate(? according to xmlschema id user1.mysample))";

Se o arquivo XML de entrada contiver dados que são válidos segundo o esquema especificado, o DB2 inserirá a linha. Caso contrário, toda a instrução falhará e nenhum dado relativo a essa linha será inserido.

Inserir uma cadeia de caractere sem validação

O método insertString() mostrado na Listagem 5 mostra como inserir um documento XML bem formado atribuído a uma variável de cadeia de caractere no DB2. A lógica não é muito diferente da utilizada no exemplo anterior para inserir dados de um arquivo. Em vez de usar o método setBinaryStream() da sua instrução preparada, use o método setString(). Para simplificar, o documento XML na definição da variável xml foi codificado permanentemente neste exemplo.

Observação: Caracteres de escape (barras invertidas) são incluídos antes das aspas que fazem parte do documento XML (como o número da versão de XML no exemplo a seguir).

Listagem 6. Inserir dados XML de uma cadeia de caractere
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) { . . . }
}

Inserir uma cadeia de caractere com validação

Como seria de se esperar, a validação de documentos XML fornecidos como cadeias de caractere exige um mínimo de programação adicional. De fato, apenas uma linha de código precisa ser modificada -- a definição da variável query. Você simplesmente precisa alterar a instrução INSERT para invocar a função XMLValidate, como foi feito na Listagem 5.

Aqui está a instrução revisada:

Listagem 7. Inserindo dados XML a partir de uma cadeia de caractere com validação
String query = "INSERT INTO clients (id, name, status contactinfo) " +
    "VALUES (?, ?, ?, xmlvalidate(? according to xmlschema id user1.mysample))";

Consultar dados XML

Agora que já sabe como inserir dados XML no DB2 usando um programa Java, você está pronto para consultar dados XML. Há vários exemplos passo a passo nesta seção, começando por uma tarefa simples (como recuperar um documento XML completo) e avançado para tarefas mais difíceis (como retornar partes de documentos XML com base em predicados de consulta XML e relacional).

Embora o DB2 suporte tanto SQL como XQuery como linguagens de nível superior, XQuery não fornece uma maneira de resolver marcadores de parâmetro. Na prática, isto significa que qualquer XQuery em seu aplicativo que exija mais que predicados de consulta codificados permanentemente deverá ser agrupada a uma instrução SQL usando uma função SQL/XML como XMLQuery ou XMLExists. "Get off to a fast start with DB2 9, Part 3: Query DB2 XML data with SQL" (developerWorks, março de 2006) discute mais detalhadamente essas funções. Aqui você aprenderá a usá-las em um programa Java. Além disso, apenas como diversão, você também verá como incluir uma XQuery com predicados de consulta codificados permanentemente em um aplicativo.

Recuperar documentos XML completos

Nosso primeiro método baseado em consulta é bem simples. Ele simplesmente recupera todas as informações de contato de um determinado cliente. Um consulta dessa natureza pode ser expressa facilmente em SQL. Portanto, se está familiarizado com JDBC, você não terá qualquer dificuldade para compreender esse código.

O método simpleQuery() na Listagem 8 declara diversas variáveis e, em seguida, estabelece uma conexão com o banco de dados usando um método auxiliar definido na Listagem 2. A cadeia de caractere query contém uma instrução SQL simples para selecionar todas as informações de contato de um cliente específico. Depois de executar a instrução, o aplicativo imprime os resultados recuperados em uma variável de cadeia de caractere (stringDoc).

Listagem 8. Recuperando documentos XML completos com 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 uma única linha de dados contendo todas as informações de contato em XML do cliente especificado.

Embora não seja mostrado aqui, também é possível usar XQuery para recuperar um ou mais documentos XML inteiros, contanto que não seja necessário incorporar marcadores de parâmetro à XQuery. Mais adiante neste artigo, você verá um trecho em Java que usa XQuery para recuperar dados XML.

Recuperar partes de documentos XML

Uma tarefa comum de programação é recuperar partes de documentos XML. O código Java neste exemplo recupera os nomes e endereços de e-mail principais dos clientes cujo status é "Silver". As informações de nome e status do cliente são armazenadas em colunas SQL VARCHAR, enquanto os endereços de e-mail estão contidos em documentos XML na coluna "contactinfo".

Para economizar espaço, omiti o código mostrado anteriormente, incluindo apenas as linhas que são novas ou diferentes.

Listagem 9. Recuperando dados relacionais e fragmentos XML com 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 uma instrução SQL/XML que chama a função XMLQuery. Ele fornece a essa função uma expressão de caminho que faz o DB2 navegar até o primeiro elemento "email" abaixo do elemento raiz "Client" nos documentos XML de destino. (Observe que a expressão de caminho faz distinção entre maiúsculas e minúsculas.) A variável $c e a cláusula SQL FROM indicam onde esses documentos de destino podem ser encontrados -- na coluna "contactinfo" da tabela "clients". A cláusula SQL WHERE restringe ainda mais os documentos XML de destino para apenas aqueles encontrados em linhas nas quais o "status" do cliente tem um certo valor (neste método, "Silver").

A saída desse programa poderá ser semelhante a esta:

Listagem 10. Exemplo de saída do aplicativo anterior
Name: Lisa Hansen   Email:  

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

Neste exemplo de saída, nenhuma informação de e-mail foi retornada para um cliente qualificado (Lisa Hansen) porque esse elemento não existe em seu documento XML "contactinfo".

Filtragem baseada em predicados relacionais e XML

Programas Java também podem instruir o DB2 para filtrar a saída da consulta com base em condições aplicáveis a dados tanto XML como não-XML. O exemplo a seguir parte do anterior para retornar os nomes e endereços de e-mail principais dos clientes "Silver" que residem em San Jose, Califórnia. Essa consulta única está projetando dados de colunas XML e não-XML e restringindo os dados com base no conteúdo de colunas tanto XML como não-XML.

O trecho a seguir inclui somente as partes do código que foram alteradas a partir do exemplo anterior. No caso, a instrução SELECT agora invoca XMLExists como parte da cláusula WHERE para restringir os resultados aos clientes que residem na cidade e estado especificados (definidos nas variáveis city e state, respectivamente).

Listagem 11. Filtrando dados XML com base nos 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); 
   . . . 
}

Como boa parte da consulta deve ser familiar para você, esta seção concentra-se apenas em suas quatro últimas linhas. A função XMLExists instrui o DB2 a determinar se um dado documento XML contém um endereço de cliente que inclua uma cidade e estado específicos. A cláusula PASSING especifica onde os documentos XML podem ser encontrados: na coluna "contactinfo". A função CAST é chamada duas vezes para converter os valores dos parâmetros de entrada (cidade e estado) para os tipos de dados apropriados.

A saída desse programa é semelhante à saída mostrada na Listagem 9, presumindo-se que tanto Lisa Hansen como Amy Liu residam em San Jose, Califórnia.

Usar XQuery como linguagem de nível superior

Embora o DB2 ofereça suporte pleno a XQuery como linguagem de nível superior, a especificação inicial de XQuery não contemplava os marcadores de parâmetro. Na prática, isso restringe o uso de XQueries em aplicativos Java. As seções anteriores mostraram como integrar XQueries a SQL (usando as funções XMLQuery e XMLExists, por exemplo) para incorporar marcadores de parâmetro. Esta seção mostra o que pode ser feito com XQuery pura em aplicativos Java.

O exemplo a seguir contém uma XQuery semelhante à apresentada em "Get off to a fast start with DB2 9, Part 4: Query DB2 XML Data with XQuery" (developerWorks, abril de 2006). Esta XQuery determina quais clientes residem em San Jose, Califórnia. Para cada cliente qualificado, ela constrói um fragmento XML contendo um "emailList" que inclui todos os endereços de e-mail desse cliente. Finalmente, ela retorna uma sequência de emailLists.

Listagem 12. Recuperando fragmentos XML com 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 
     . . . 
}

Há dois aspectos dignos de nota nessa consulta. Em primeiro lugar, a cadeia de caractere de consulta começa com a palavra-chave "xquery". Isso instrui o DB2 a usar seu analisador de XQuery para processar a consulta. Você terá que fazer isso sempre que usar XQuery como a linguagem mais externa. Em segundo lugar, a consulta refere-se aos nomes de tabela e de coluna em maiúsculas. A linguagem XQuery faz distinção entre maiúsculas e minúsculas. Como o DB2 geralmente coloca os nomes de tabela e de coluna em maiúsculas ao gravar essas informações em seus catálogos internos, a XQuery deve ser compatível com essas informações.

Um exemplo da saída desse programa é mostrado na Listagem 13. Como um item "emailList" é retornado para cada cliente qualificado, uma varredura rápida dessa saída indica que havia quatro clientes qualificados. O primeiro registro qualificado contém um endereço de e-mail. O segundo não contém nenhum (talvez porque o cliente não forneceu essa informação); consequentemente, seu emailList está vazio. O terceiro registro qualificado indica que há dois endereços de e-mail registrados para esse cliente. O quarto contém um endereço de e-mail para o cliente.

Listagem 13. Exemplo de saída do aplicativo 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>

Talvez você esteja se perguntando por que os nomes de cada cliente qualificado não foram incluídos nos resultados. A resposta é simples: XQuery trabalha com dados XML e os nomes dos clientes estão armazenados em uma coluna SQL VARCHAR . Portanto, para que a saída incluísse os nomes dos clientes qualificados juntamente com seus endereços de e-mail, seria necessário escrever uma consulta incluindo tanto SQL como XQuery.

Atualizar e excluir dados XML

Para atualizar e excluir dados XML armazenados no DB2, são usadas as instruções SQL UPDATE e DELETE. Essas instruções podem incluir funções SQL/XML que restrinjam as linhas e colunas de destino com base em valores de elementos XML armazenados em colunas XML. Por exemplo, é possível excluir as linhas que contêm informações sobre clientes que residem em um CEP específico ou atualizar somente os dados XML (e não-XML) de clientes que residem em um determinado estado.

Como a sintaxe de uso de funções SQL/XML em instruções UPDATE e DELETE é idêntica à de instruções SELECT, não são repetidos aqui os exemplos de código por extenso. Em vez disso, são incluídos apenas pequenos trechos. Consideraremos primeiramente as operações DELETE.

Exemplos de exclusão

É fácil excluir uma linha que contém dados XML. Basta usar a instrução SQL DELETE com uma cláusula WHERE (se desejado) para restringir as linhas a serem excluídas. Por exemplo, o código a seguir exclui a linha do cliente cujo ID é 1885:

Listing 14. Deleting data based on a relational data value
. . . 
 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."); }
 . . .

Para restringir suas operações DELETE com base nos valores de elementos XML, simplesmente invoque as funções SQL/XML apropriadas na cláusula WHERE. A Listagem 14 usa a função XMLExists para especificar que as informações de todos os clientes que residem em Maine (abreviado como "ME") devem ser excluídas:

Listagem 15. Excluindo dados com base no valor de um 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);
. . .

Exemplos de atualização

Com o DB2 9, é possível atualizar dados em uma coluna XML usando a instrução SQL UPDATE ou um procedimento armazenado como DB2XMLFUNCTIONS.XMLUPDATE. Em ambos os casos, as atualizações da coluna XML ocorrem em nível de documento e não em nível de elemento. Entretanto, os programadores que atualizam dados usando o procedimento armazenado não precisam fornecer o documento XML completo ao DB2. Eles só têm que especificar os elementos XML a serem atualizados; o DB2 preserva os dados inalterados do documento e atualiza os elementos especificados. Os programadores que emitem instruções UPDATE devem especificar o documento completo (e não apenas os elementos que desejam alterar).

Parte do DB2 release 9.5, porém, simplificou substancialmente a atualização de documentos XML existentes. Nesse release, implementamos uma nova função XQuery chamada "Transform". Essa função expandiu a linguagem XQuery inicial para além das consultas simples a XML, permitindo que ela atualize dados XML.

A Listagem 16 atualiza as informações de contato do cliente cujo ID é 1333 usando os dados XML contidos em um arquivo. Observe que os novos dados XML são validados contra um esquema registrado como parte da operação de atualização:

Listagem 16. Atualizando dados XML a partir de um arquivo
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());
. . .

Evidentemente, também é possível usar um predicado de consulta XML para especificar um ou mais registros de contato de cliente a serem atualizados. Novamente, para fazer isso é necessário usar funções SQL/XML. Imagine que uma cliente deseja que seu número de fax seja atualizado mas não lembra seu ID de cliente. Em vez disso, ela fornece seu número de telefone residencial para nos ajudar a localizar suas informações. O trecho de código a seguir usa XMLExists para restringir as atualizações apenas ao registro que contém o número de telefone residencial da cliente. Observe que as informações de contato completas da cliente são fornecidas como uma cadeia de caractere Java contendo o documento XML revisado. Esse é o método que deve ser empregado com o DB2 9.1. No DB2 9.5, porém, foi adicionada uma nova função W3C chamada XML Transform ou Update. Essa nova função, atualmente com status de recomendada, permite atualizar um nó, excluir um nó, substituir um nó ou modificar um nó. A função transform exige uma sintaxe específica, que é mostrada na Listagem 17b. Com essa nova função, você basicamente obtém um instantâneo de um documento XML existente, faz as modificações desejadas e o substitui pela versão alterada. A Listagem 17b mostra a diferença com o DB2 9.5 e a nova função Transform.

Listagem 17. Atualizando dados XML com uma cadeia de caractere
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);
. . .
Listagem 17b. Atualizando dados XML com uma cadeia de caractere com DB2 V9.5 e a função XQuery Transform.
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);
. . .

Gerador de consultas

Se você precisar de ajuda para escrever consultas para o seu aplicativo, o Developer Workbench fornece assistentes que geram SQL/XML e XQueries. Como a maioria dos programadores Java escreve aplicativos que exigem marcadores de parâmetro, eles frequentemente usam SQL/XML. Esta seção descreve passo a passo um breve exemplo do uso do gerador de consultas SQL para gerar uma instrução SQL/XML semelhante à incluída na Listagem 9.

Para gerar uma instrução SQL/XML, execute as seguintes etapas:

  1. Prepare sua área de trabalho.
  2. Especifique as características da consulta.
  3. Execute a consulta.

Agora examinaremos detalhadamente cada uma dessas etapas.

Prepare sua área de trabalho

As instruções SQL são criadas como parte de um "projeto Data" acessível a partir da perspectiva Data da área de trabalho. Para criar esse projeto, execute as seguintes etapas:

  1. Abra a perspectiva Data. Selecione Window > Open Perspective > Other > Data.
  2. Crie uma conexão com o banco de dados de destino. Clique com o botão direito do mouse dentro do painel Database Explorer, no canto inferior esquerdo. Selecione New Connection e especifique o nome do banco de dados e seu nome de usuário e senha.
  3. Crie um novo projeto Data. Clique com o botão direito do mouse dentro do painel Data Project Explorer, no canto superior esquerdo. Selecione New > Project > Data > Data Development Project. Quando solicitado, forneça o nome de sua escolha para o projeto e associe-o à conexão com o banco de dados criada anteriormente.

Com uma conexão com o banco de dados aberta e um projeto Data criado, você está pronto para gerar consultas.

Gere a sua consulta

Para manter este tutorial simples, criaremos uma instrução SQL/XML que retorne o endereço de e-mail principal de clientes que têm um certo status. A consulta será semelhante a esta:

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

Siga estas etapas para gerar a consulta:

  1. Inicie o SQL Builder. Em seu projeto Data, realce a pasta SQL Scripts e clique com o botão direito do mouse. Selecione New > SQL Statement. Ao ser solicitado, aceite o nome padrão para o projeto e especifique um nome para a instrução SQL. Aceite o padrão para o tipo de instrução (SELECT) e opte pelo uso do SQL Builder. Clique em Finish.
  2. Especifique a tabela a ser consultada. Clique com o botão direito do mouse no painel central e selecione Add Table. Expanda a pasta do seu esquema e selecione a tabela "clients".
  3. Especifique as colunas de interesse. Para este exemplo, você deverá incluir uma coluna e a saída de uma função (XMLQuery) no conjunto de resultados. Para fazer isso, conclua as seguintes etapas:
    1. Marque a coluna "names" exibida no painel central.
    2. Clique na primeira linha exibida na guia Column, abaixo do painel central. Clique no canto superior direito dessa célula para exibir uma tecla de seta e selecione Build Expression. Pressione Enter.
    3. Selecione Function no menu exibido.
    4. Selecione XML como a categoria da função e XMLQuery como a função. Ao lado de Parameter Value 1, clique na seta na célula Value e selecione Edit Expression.
    5. Especifique a expressão de caminho apropriada no String Constant Builder: $c/Client/email[1], e clique duas vezes em Finish.
    6. Altere a instrução SQL gerada para incluir uma cláusula PASSING na função XQuery. A função XQuery final deverá ter o seguinte conteúdo: '$c/Client/email[1]' passing contactinfo as "c"
  4. Especifique o predicado da consulta (cláusula WHERE). Para este exemplo, você deverá adicionar um predicado de consulta para uma coluna relacional.
    1. Na guia Conditions, abaixo da sua instrução SQL/XML, clique na primeira linha exibida na guia Column. Clique na tecla de seta na extremidade direita dessa célula e selecione a coluna status.
    2. Clique na célula Operator e selecione o operador de igualdade ("=").
    3. Clique na tecla de seta na extremidade direita da célula Value e selecione Build Expression. Pressione Enter.
    4. Selecione Constant e depois String Constant ao ser solicitado.
    5. Especifique o nome de uma variável de host (como "status") para entrada do usuário. Clique em Finish.

Execute a consulta

Depois de construir a consulta, você estará pronto para executá-la.

  1. Localize a consulta no seu projeto Data, clique com o botão direito do mouse e selecione Run SQL.
  2. Ao ser solicitado, especifique um valor de entrada (como "Gold" ou "Silver") para o status do cliente e clique em OK.
  3. Revise os resultados no painel Data Output.

Procedimentos armazenados

Em ambientes de rede, os procedimentos armazenados frequentemente reduzem a comunicação necessária entre os aplicativos clientes e o DB2. Isso, evidentemente, melhora o desempenho em tempo de execução. Com o DB2 9, os procedimentos armazenados podem incluir variáveis e parâmetros XML.

Embora esteja além do escopo deste artigo discutir em detalhes o desenvolvimento de procedimentos armazenados, é fornecida uma revisão com um cenário simples para lhe mostrar como um procedimento armazenado DB2 pode ser escrito para recuperar partes de documentos XML. Esse cenário usa assistentes do Data Studio para gerar, implementar e executar o código SQL necessário do procedimento armazenado. Se preferir, você poderá desenvolver e implementar um procedimento armazenado SQL equivalente usando o processador de linha de comando do DB2. Também é possível escrever procedimentos armazenados baseados em XML em Java.

Para este exemplo, você escreverá um procedimento armazenado que recupera os nomes e endereços de e-mail principais de clientes com um determinado status, como foi feito anteriormente. Embora este seja muito simples, este procedimento o ajudará a entender como gerar procedimentos baseados em SQL que consultam e retornam dados XML usando assistentes integrados.

Para criar esse procedimento, execute algumas etapas simples:

  1. Prepare sua área de trabalho.
  2. Especifique o conteúdo do procedimento.
  3. Implemente e teste o procedimento.

Agora examinaremos detalhadamente cada uma dessas etapas.

Prepare sua área de trabalho

Os procedimentos armazenados são definidos como parte de um projeto Data. Se ainda não fez isso, abra a perspectiva Data, estabeleça uma conexão com o banco de dados e crie um projeto Data. Para obter mais detalhes, consulte a seção Prepare sua área de trabalho anterior.

Crie o procedimento

Nosso procedimento armazenado baseado em SQL invoca uma única instrução SQL/XML que consulta a tabela "clients" com base na entrada fornecida pelo iniciador da chamada. Esse procedimento retorna um único conjunto de resultados contendo uma coluna SQL VARCHAR (para o nome do cliente) e uma coluna XML (para o e-mail do cliente). A consulta será semelhante a esta:

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

O processo de construção de um procedimento armazenado SQL que acessa dados XML não é diferente do empregado para construir um procedimento SQL que acessa dados não-SQL. Aqui está uma maneira de fazer isso:

  1. Defina um novo procedimento armazenado. Expanda o novo projeto Data, realce Stored Procedures e clique com o botão direito do mouse. Selecione New > Stored Procedure. Siga os prompts para confirmar o nome do projeto e especificar o nome do procedimento armazenado. Mantenha o tipo de linguagem padrão como SQL.
  2. Especifique sua(s) instrução(ões) SQL. Ao ser solicitado, você poderá digitar a instrução de consulta diretamente ou usar os assistentes para ajudá-lo a criar uma. As etapas a seguir são para a segunda opção.
    1. Clique em Create SQL.
    2. Aceite os padrões para o tipo de instrução (SELECT) e processo de desenvolvimento (criação da instrução guiada por assistentes).
    3. Selecione a tabela clients como o alvo da instrução.
    4. Na guia Columns, inclua duas colunas no conjunto de resultados final. Selecione names e depois Add > Function > Next. Na janela seguinte, especifique a categoria da função como XML e XMLQuery como assinatura da função. Clique em Finish.
    5. Na guia Conditions, construa a cláusula SQL WHERE. Especifique clients.status como a coluna, igual a ("=") como o operador e :input como o valor.
    6. Modifique a instrução SQL resultante para incluir a expressão de caminho apropriada para recuperar o primeiro endereço de e-mail na coluna "contactinfo". Especificamente, altere a linha XMLQUERY para que fique com o seguinte conteúdo: xmlquery('$c/Client/email[1]' passing contactinfo as "c")
    7. Analise a consulta para verificar se não há erros de sintaxe.
  3. Especifique as informações de implementação. Em particular, talvez seja útil habilitar a depuração (Enable Debugging).
  4. Opcionalmente, revise o código SQL gerado. Clique em Show SQL. (Consulte a Listagem 20 para ver um exemplo do que deverá aparecer.)
  5. Conclua o procedimento armazenado. Clique em Finish.
Listagem 20. Exemplo do código gerado para o procedimento armazenado SQL envolvendo dados 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

Implemente e teste o procedimento

Tendo criado o procedimento, você estará pronto para implementá-lo e testá-lo. Siga estas etapas:

  1. Implemente o procedimento. Localize o procedimento no seu projeto Data, clique com o botão direito do mouse e selecione Deploy. Aceite as configurações padrão e clique em Finish. O painel Data Output, no cano inferior direito, deverá informar que o procedimento foi implementado com êxito.
  2. Execute o procedimento. Localize o procedimento no seu projeto Data, clique com o botão direito do mouse e selecione Run. Ao ser solicitado, especifique um valor de entrada (como "Gold" ou "Silver") para o status do cliente. Clique em OK e visualize os resultados do procedimento armazenado no painel Data Output.

Opcionalmente, o procedimento armazenado poderá ser chamado de fora do Developer Workbench. Por exemplo, se atribuiu ao procedimento o nome "getInfo", você poderá invocar o processador de linha de comando do DB2, conectar-se ao banco de dados e emitir a seguinte instrução:

Listagem 21. Invocando o procedimento armazenado
 call getInfo('Silver')

Resumo

Ao escrever aplicativos Java que trabalhem com dados XML do DB2, você usará código JDBC familiar para executar consultas e processar seus resultados. A IBM fornece ferramentas como o Data Studio, um ambiente de trabalho do desenvolvedor baseado em Eclipse, para ajudá-lo a codificar, testar e depurar o seu trabalho. O Data Studio inclui assistentes para explorar o conteúdo do banco de dados, escrever procedimentos armazenados que acessam dados XML e não-XML, XQueries que acessam dados XML e instruções SQL/XML que acessam dados XML e não-XML.

Agradecimentos

Obrigado a Don Chamberlin, Grant Hutchison e Brian Payton pela revisão deste artigo.

Recursos

Aprender

Obter produtos e tecnologias

  • Elabore seu próximo projeto de desenvolvimento com o software de teste IBM, disponível para download diretamente no developerWorks.
  • Agora é possível usar o DB2 gratuitamente. Faça o download do DB2 Express-C, uma versão sem custos do DB2 Express Edition para a comunidade, que oferece os mesmos recursos principais de dados do DB2 Express Edition e fornece uma base sólida para construir e implementar aplicativos.

Discutir

Comentários

developerWorks: Conecte-se

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


Precisa de um ID IBM?
Esqueceu seu ID IBM?


Esqueceu sua senha?
Alterar sua senha

Ao clicar em Enviar, você concorda com os termos e condições do developerWorks.

 


A primeira vez que você entrar no developerWorks, um perfil é criado para você. Informações no seu perfil (seu nome, país / região, e nome da empresa) é apresentado ao público e vai acompanhar qualquer conteúdo que você postar, a menos que você opte por esconder o nome da empresa. Você pode atualizar sua conta IBM a qualquer momento.

Todas as informações enviadas são seguras.

Elija su nombre para mostrar



Ao se conectar ao developerWorks pela primeira vez, é criado um perfil para você e é necessário selecionar um nome de exibição. O nome de exibição acompanhará o conteúdo que você postar no developerWorks.

Escolha um nome de exibição de 3 - 31 caracteres. Seu nome de exibição deve ser exclusivo na comunidade do developerWorks e não deve ser o seu endereço de email por motivo de privacidade.

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

(Escolha um nome de exibição de 3 - 31 caracteres.)

Ao clicar em Enviar, você concorda com os termos e condições do developerWorks.

 


Todas as informações enviadas são seguras.


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=80
Zone=Information Management
ArticleID=483305
ArticleTitle=Tenha um início rápido com o DB2 9 pureXML, Parte 5: Desenvolva aplicativos Java para dados XML do DB2
publish-date=04162010