Provavelmente quando você ouve falar de JDBC, você deve imaginar o seguinte código:


Connection conn = getConnection();
 PreparedStatetemt p = conn.prepareStatement("select * from AnyTable");
 ResultSet rs = p.executeQuery();
 while(rs.next()) {
       // mapeia o ResultSet para algum conjunto de objetos
 }

Muita gente imagina que JDBC é apenas isso, o que é uma pena. E é uma pena pois ao Java SE 5.0 passou a suportar o JDBC 3.0 (sob o pacote javax.sql), oferecendo uma nova API para facilitar a vida dos desenvolvedores na manipulação e transformação de dados. Neste artigo, vamos ver como manipular os resultados de uma consulta de maneira desconectada do banco de dados, usando o CachedRowSet, e como transformar seus dados em XML e vice-versa, usando WebRowSet.

Ando meio desligado...

Manter uma conexão com o banco de dados aberta por muito tempo pode não ser uma boa estratégia em alguns casos, pois isso reduz a escalabilidade do banco de dados, uma vez que conexão é um recurso limitado. No entanto, algumas vezes é preciso que você manipule alguns dados durante um longo tempo e consista estas atualizações no seu repositório novamente (como pode ser o caso de uma aplicação rich client). Neste caso, trabalhar com o seu conjunto de dados de maneira desconectada do banco é a melhor solução. Contudo, usando a API clássica do JDBC, seria necessário mapear os dados retornados por uma consulta SQL em um ResultSet para objetos Java, desconectar-se do banco de dados, atualizar estes objetos, conectar-se ao banco novamente e reenviar os novos dados - uma tarefa muito trabalhosa e propensa a erros. Porém, se você utilizar um CachedRowSet, esta tarefa se torna "brincadeira de criança".

A interface javax.sql.CachedRowSet, cuja principal implementação é feita pela Sun Microsystems (sob o pacote com.sun.rowset), representa um conjunto de dados resultantes de uma consulta, bem similar à interface java.sql.ResultSet, com uma sutil diferença: quando a conexão com o banco de dados é fechada, um CachedRowSet mantém uma cópia dos dados acessível offline, permitindo que você os manipule mesmo que você já esteja desconectado do seu servidor de banco de dados. Além disso, o CachedRowSet (como todo objeto que estende a interface javax.sql.RowSet) permite que você altere e navegue através do conjunto de dados que ele armazena.

Para ilustrar o uso básico do CachedRowSet, abaixo temos um simples teste que mostra algumas de suas funcionalidades básicas, como iteração, atualização e renovação de dados.


package org.nullability.rowset.demo;

import static java.lang.System.out;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

import javax.sql.rowset.CachedRowSet;

import com.sun.rowset.CachedRowSetImpl;

public class CachedRowSetDemo {

  public static void main(String... args) throws Exception{
    Connection conn = getConnection();
    PreparedStatement p = conn.prepareStatement("SELECT * FROM SOME_TABLE");
    ResultSet rs = p.executeQuery();
    CachedRowSet wrs = new CachedRowSetImpl(); // criando nosso CachedRowSet
    wrs.populate(rs); // preenchendo com dados da consulta
    p.close();
    conn.close(); // fechando a conexão
    while(wrs.next()){
       out.printf("%s: %d - %s: %d \n", wrs.getMetaData().getColumnName(1), wrs.getInt(1), 
       wrs.getMetaData().getColumnName(2), wrs.getInt(2));
       wrs.updateInt(2,10); // atualiza a segunda coluna da linha atual com o valor "10"
       wrs.updateRow(); // efetiva a atualização sobre o modelo
    }
    wrs.absolute(2); // posiciona o cursor sobre a segunda linha 
    wrs.deleteRow(); // remove a linha para a qual o cursor está apontando
    conn = getConnection();
    wrs.acceptChanges(conn); // efetiva as alterações no banco de dados
    wrs.close();            
    conn.close();
  }

  private static Connection getConnection() throws ClassNotFoundException, SQLException {
            Class.forName("");
            Connection conn = DriverManager.getConnection("SUA STRING DE CONEXAO");
            return conn;
  }
}

Pronto. Sem necessidade de fazer mapeamentos temporários, conseguimos manipular nossos dados e refletir estas alterações no banco de dados de maneira bem simples. Mas, e se quiséssemos exportar nossos dados para um outro formato, como XML?

Então você quer XML?

Então você vai precisar trabalhar com um WebRowSet. Assim como o CachedRowSet, o WebRowSet permite que você manipule dados de uma consulta de maneira desconectada do banco de dados. Adicionalmente, o WebRowSet permite que você exporte e importe dados para um formato XML pré-definido (a definição do schema está aqui), dividido em três partes: propriedades, meta-dados e dados. Abaixo, temos um exemplo simples de como exportar um conjunto de dados para XML a partir de um WebRowSet.


package org.nullability.rowset.demo;

import java.io.FileOutputStream;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

import javax.sql.rowset.WebRowSet;

import com.sun.rowset.WebRowSetImpl;

public class WebRowSetDemo {

  /**
   * @param args
   */
  public static void main(String... args) throws Exception{
    Connection conn = getConnection();
    PreparedStatement p = conn.prepareStatement("SELECT * FROM SOME_TABLE");
    ResultSet rs = p.executeQuery();
    WebRowSet wrs = new WebRowSetImpl();
    wrs.populate(rs);
    p.close();
    conn.close();
    wrs.writeXml(new FileOutputStream("output.xml"));
    wrs.close();            
  }

  private static Connection getConnection() throws ClassNotFoundException, SQLException {
    Class.forName("");
    Connection conn = DriverManager.getConnection("SUA STRING DE CONEXAO");
    return conn;
  }
}

Por que deveria usar?

Os motivos principais para se usar tanto o CachedRowSet quanto o WebRowSet são:

  • Facilidade para manipulação de dados
  • Menor quantidade de atualizações sendo feitas diretamente no banco
  • Facilidade para transformação de dados para um outro formato, sendo possível utilizar um WebRowSet para a criação de RESTful Web Services simples

Ainda assim, é preciso ficar atento a dois pontos:

  • Concorrência na atualização de dados, uma vez que, tanto no caso do CachedRowSet quanto no caso do WebRowSet, os dados são manipulados offline
  • Versão nova do JDK, uma vez que o suporte ao JDBC 3.0 só existe a partir do Java SE 5.0

Bom, e por enquanto é isso. Até a próxima.