Baixar Aulas 07 e 08
Transcrição
Baixar Aulas 07 e 08
Programação para Internet II Aulas 07 e 08 Fernando F. Costa professor.fimes.edu.br/fernando [email protected] Como tratar de grandes conjuntos de resultados Quando temos uma grande quantidade de registros a ser exibida para um usuário, provavelmente não vamos querer que todos eles sejam carregados e exibidos de uma única vez. Uma alternativa seria filtrar a consulta para reduzir os dados a serem exibidos. Contudo paginar os resultados em pequenas quantidades também pode ser uma boa solução. A interface RowSet Uma boa alternativa para trabalhar com a paginação de resultados é fazer uso da interface RowSet que foi introduzida na especificação JDBC 2.0 para definir um meio padrão para acessar dados armazenados em cache através de um componente JavaBeans ou através de sistemas distribuídos. O Bean CachedRowSet Portanto, para tratar consultas que são maiores que uma tela inteira e não tão grande para serem verdadeiras devoradoras de memória, o Bean CachedRowSet se mostra como boa opção. Ele faz parte da interface RowSet contida na implementação JDBC 2.0 fornecida pela Sun. O Bean CachedRowSet Diferente de ResultSet, CachedRowSet é uma conexão offline que armazena em cache todas as linhas de sua consulta no objeto. Nenhuma conexão ativa é necessária porque todos os dados foram pegos do banco de dados. Para fazer uso deste Bean, basta configurar suas propriedades de acesso ao Banco, sua consulta SQL e pronto. A partir deste ponto é só navegar pelos resultados obtidos. Exemplo Prático Vejamos como trabalhar com a paginação de resultados em JSP utilizando o Bean CachedRowSet. Para isto, crie um novo projeto web chamado Conferencia. No MySQL crie uma base de dados chamada conf para ilustrar nosso exemplo. Exemplo Prático No MySQL, digite os seguintes comandos para criar o banco e as tabelas. create database conf; create table conference( id integer not null auto_increment, cidade varchar(80), aeroporto char(3), assentos integer, primary key (id) ); create table shuttles( id integer not null auto_increment, aeroporto char(3), hora time, assentos integer, primary key (id) ); Exemplo Prático Digite os seguintes comandos para preencher as tabelas criadas: INSERT 45); INSERT 'LAX', INSERT 0); INSERT 11); INSERT 0); INSERT 'SFO', INSERT INSERT INSERT INSERT INSERT INSERT INSERT INSERT INSERT INTO conference (cidade, aeroporto, assentos) VALUES ('Austin', 'AUS', INTO conference (cidade, aeroporto, assentos) VALUES ('Las Angeles', 37); INTO conference (cidade, aeroporto, assentos) VALUES ('New York', 'JFK', INTO conference (cidade, aeroporto, assentos) VALUES ('Houston', 'IAH', INTO conference (cidade, aeroporto, assentos) VALUES ('Boston', 'BOS', INTO conference (cidade, aeroporto, assentos) VALUES ('San Francisco', 12); INTO INTO INTO INTO INTO INTO INTO INTO INTO shuttles shuttles shuttles shuttles shuttles shuttles shuttles shuttles shuttles (aeroporto, (aeroporto, (aeroporto, (aeroporto, (aeroporto, (aeroporto, (aeroporto, (aeroporto, (aeroporto, hora, hora, hora, hora, hora, hora, hora, hora, hora, assentos) assentos) assentos) assentos) assentos) assentos) assentos) assentos) assentos) VALUES VALUES VALUES VALUES VALUES VALUES VALUES VALUES VALUES ('AUS', ('AUS', ('AUS', ('LAX', ('LAX', ('IAH', ('JFK', ('BOS', ('SFO', '9:40', 10); '12:00', 12); '14:15', 0); '12:15', 10); '16:35', 10); '9:30', 0); '12:15', 10); '16:35', 10); '9:30', 10); Exemplo Prático Concluído a parte de criação e preenchimento do banco, é hora de criarmos nosso arquivo JSP que fará a paginação dos resultados obtidos. No exemplo a seguir, os resultados serão paginados de 5 em 5 registros. Você pode definir a quantidade que desejar, basta definir no loop quantos registros serão exibidos por vez. Exemplo Prático CachedResults.jsp (parte 1/3) <%@page import="java.sql.*" %> <%@page import="javax.sql.*" %> <%@page import="com.sun.rowset.*" %> <jsp:useBean id="crs" class="com.sun.rowset.CachedRowSetImpl" scope="session"> <% try { Class.forName("com.mysql.jdbc.Driver"); } catch (ClassNotFoundException e) { System.err.println("Error" + e); } %> <jsp:setProperty name="crs" property="url" value="jdbc:mysql://localhost:3306/conf" /> <jsp:setProperty name="crs" property="username" value="root" /> <jsp:setProperty name="crs" property="password" value="adminadmin" /> <jsp:setProperty name="crs" property="command" value="select * from shuttles order by id" /> <% try { crs.execute(); } catch (SQLException e) { out.println("SQL Error: " + e); } %> </jsp:useBean> Exemplo Prático <html> CachedResults.jsp (parte 2/3) <body> <center> <h2>Resultados da Consulta em Cache</h2> <P> <table border="2"> <tr bgcolor="tan"> <th>ID</th><th>Aeroporto</th><th>Hora de Partida </th><th>Assentos</th></tr> <% try { if ("first".equals(request.getParameter("action"))) crs.beforeFirst(); for (int i=0; (i < 5) && crs.next(); i++) { %> <tr> <td><%= crs.getString("id") %></td> <td><%= crs.getString("aeroporto") %></td> <td><%= crs.getString("hora") %></td> <td><%= crs.getString("assentos") %></td> </tr> <% } %> </table> Exemplo Prático CachedResults.jsp (parte 3/3) <br> <% if (crs.isAfterLast()) { crs.beforeFirst(); %> Fim dos registros<br><br> <% } } catch (SQLException e) { out.println("SQL Error" + e); } %> <a href="<%= HttpUtils.getRequestURL(request) %>?action=first"> [Início]</a> <a href="<%= HttpUtils.getRequestURL(request) %>?action=next"> [Próximo]</a> </center> </body> </html> Resultado Esperado Trabalho em Grupo (3 pessoas) Valor: 2,0 pontos Data apresentação: 11/04/2011 Descrição: Utilizando os conceitos já apresentados, e enfatizando o conceito de Beans e Rowset, crie uma aplicação web para fazer o controle de produtos de uma empresa. A aplicação web deve conter uma parte administrativa na qual deverá ser possível: ● Cadastrar, Alterar e Remover um produto Na parte de usuário, deve existir apenas uma lista dos produtos cadastrados com as respectivas informações: ● Nome (String) ● Preço (Double) ● Quantidade (Integer) Quando o usuário clicar em comprar um produto, ele deve informar a quantidade. Após confirmar a quantidade, a aplicação deve remover esta quantidade do estoque. Observações: ● A área administrativa só pode ser acessada mediante login. ● Não deve ser permitido a compra de uma quantidade superior a quantidade em estoque. ● Se um produto estiver esgotado (quantidade = 0) deve aparecer a mensagem esgotado no local do preço e não deve ser mostrado o botão Comprar. Como manter conexões persistentes A conexão com o BD normalmente é a parte mais lenta de uma aplicação web. Contudo, manter várias conexões em aberto pode ser inviável, uma vez que o banco de dados pode suportar uma quantidade limitada de conexões. Desta forma, uma boa alternativa para solucionar este impasse é fazer uso dos Pools de Conexões que são implementados pelo driver do banco de dados, ou por classes de Pool de Conexões. Pool de Conexões Os pools de conexões mantêm um número fixo de conexões ativas e as empresta quando solicitado pelas suas páginas JSP ou Beans. Logo se tornam uma boa alternativa entre ter muitas conexões abertas e pagar o preço por conexões e desconexões frequentes. Pool de Conexões A seguir veremos o código que cria um Bean responsável por encapsular uma conexão de banco de dados. Isto permite isolar nossas páginas JSP dos detalhes de conexão com o BD, assim como permite manter nossa conexão através de diversas páginas ao armazená-la na sessão. Desta maneira não precisamos sempre nos reconectar no banco de dados. ConnectionBean public class ConnectionBean implements HttpSessionBindingListener { private Connection connection; private Statement statement; private static final String driver="com.mysql.jdbc.Driver"; private static final String dbURL="jdbc:mysql://localhost:3306/conf"; private static final String login="root"; private static final String password="adminadmin"; public ConnectionBean() { } try { Class.forName(driver); connection=DriverManager.getConnection(dbURL,login,password); statement=connection.createStatement(); } catch (ClassNotFoundException e) { System.err.println("ConnectionBean: driver unavailable"); connection = null; } catch (SQLException e) { System.err.println("ConnectionBean: driver not loaded"); connection = null; } ConnectionBean public void valueBound(HttpSessionBindingEvent event) { System.err.println("ConnectionBean: in the valueBound method"); try { if (connection == null || connection.isClosed()) { connection = DriverManager.getConnection(dbURL,login,password); statement = connection.createStatement(); } } catch (SQLException e) { connection = null; } } public void valueUnbound(HttpSessionBindingEvent event) { try { connection.close(); } catch (SQLException e) { } finally { connection = null; } } } protected void finalize() { try { connection.close(); } catch (SQLException e) { } } Processamento de Transações As operações efetuadas em um BD nem sempre são atômicas, ou seja, na maioria das vezes ela envolve duas ou mais operações que precisam acontecer com sucesso para garantir a integridade do banco de dados. Ex: transação bancária. Processamento de Transações Os Bancos de Dados fornecem um mecanismo conhecido como transações para tratar deste assunto. Em JSP devemos efetuar um commit() no objeto Connection para concluir uma operação que ocorreu sem erros, ou efetuar um rollback() do objeto Connection para retornar o banco ao estado em que ele se encontrava no inicio da transação. Processamento de Transações Como padrão o JDBC assume que cada instrução SQL é uma transação, e portanto, efetua um autocommit a cada instrução que é emitida. Para que esse controle seja feito “manualmente”, devemos desativar o recurso autocommit. A seguir temos um exemplo desta situação em uma operação de transação bancária entre as contas de Bob e Sue. Desativando o recurso autocommit Observação: Lembrem-se de reativar o recurso autocommit ao concluírem suas transações. connection.setAutoCommit(false); try { Statement st = connection.createStatement(); st.executeUpdate( "UPDATE ACCTS SET BALANCE=(BALANCE-100) WHERE OWNER = "Bob"); st.executeUpdate( "UPDATE ACCTS SET BALANCE=(BALANCE + 100) WHERE OWNER = "Sue"); connection.commit(); } catch (SQLException e) { connection.rollback(); } finally { connection.setAutoCommit(true); } Exemplo Prático A seguir criaremos um exemplo para trabalhar com os assuntos tratados na aula de hoje. O objetivo do exemplo que será criado é permitir que sejam feitas reservas de vagas em conferências de computação que ocorrerão em todo o mundo. Contudo, o sistema deve garantir que além de reservar uma vaga na conferência, também seja possível reservar uma vaga na ponte aérea com destino a conferência selecionada. Exemplo Prático Neste exemplo utilizaremos o projeto Conferencia criado anteriormente, juntamente com a base de dados conf que foi criada. Exemplo Prático import java.sql.*; import javax.servlet.http.*; ConnectionBean.java (parte 1 de 3) public class ConnectionBean implements HttpSessionBindingListener { private Connection connection; private Statement statement; private static final String driver="com.mysql.jdbc.Driver"; private static final String dbURL="jdbc:mysql://localhost:3307/conf"; private static final String login="root"; private static final String password="adminadmin"; public ConnectionBean() { try { Class.forName(driver); connection=DriverManager.getConnection(dbURL,login,password); statement=connection.createStatement(); } catch (ClassNotFoundException e) { System.err.println("ConnectionBean: driver unavailable"); connection = null; } catch (SQLException e) { System.err.println("ConnectionBean: driver not loaded"); connection = null; } } Exemplo Prático ConnectionBean.java (parte 2 de 3) public Connection getConnection() { return connection; } public void commit() throws SQLException { connection.commit(); } public void rollback() throws SQLException { connection.rollback(); } public void setAutoCommit(boolean autoCommit) throws SQLException { connection.setAutoCommit(autoCommit ); } public void valueBound(HttpSessionBindingEvent event) { System.err.println("ConnectionBean: in the valueBound method"); try { if (connection == null || connection.isClosed()) { connection = DriverManager.getConnection(dbURL,login,password); statement = connection.createStatement(); } } catch (SQLException e) { connection = null; } } Exemplo Prático ConnectionBean.java (parte 3 de 3) public ResultSet executeQuery(String sql) throws SQLException { return statement.executeQuery(sql); } public int executeUpdate(String sql) throws SQLException { return statement.executeUpdate(sql); } public void valueUnbound(HttpSessionBindingEvent event) { try { connection.close(); } catch (SQLException e) { } finally { connection = null; } } } protected void finalize() { try { connection.close(); } catch (SQLException e) { } } Exemplo Prático index.jsp <%@page contentType="text/html" pageEncoding="UTF-8"%> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>JSP Page</title> </head> <body> <center> <h1>Conferência Mundial de Computação</h1> <a href="CachedResults.jsp" target="_self">Vagas Disponíveis</a><br><br> <a href="conference.jsp" target="_self">Fazer minha inscrição</a> </center> </body> </html> Exemplo Prático conference.jsp (parte 1 de 2) <%@page import="java.sql.*" errorPage="error.jsp" %> <jsp:useBean id="connection" class="com.taglib.wdjsp.databases.ConnectionBean" scope="session"/> <html> <body> <center> <font size="+2" face="arial"><b>Conferência Registros</b></font> <form action="shuttle.jsp" method="post"> <table border=1 bgcolor="tan" width="50%" align="center"> <tr> <td> <table border="0" bgcolor="white" cellspacing=0 width="100%"> <tr bgcolor="tan"> <th> </th><th>Cidade</th><th>Vagas Restantes</th></tr> <tr><% String sql = "select * from conference"; ResultSet results = connection.executeQuery(sql); while (results.next()) { if (results.getInt("assentos") > 0) { %> <td> <input type="radio" name="show" value="<%= results.getString("id") %>"> </td> <% } Exemplo Prático conference.jsp (parte 2 de 2) else { %> <td> </td> <% } %> <td><%= results.getString("cidade") %></td> <td align="center"><%= results.getString("assentos") %></td> </tr> <% } %> </table> </td> </tr> </table> <p> <input type="submit" value="Proximo (Escolher Ponte Aerea)"> </form> </center> </body> </html> Exemplo Prático shuttle.jsp (parte 1 de 2) <%@ page import="java.sql.*" errorPage="error.jsp" %> <jsp:useBean id="connection" class="com.taglib.wdjsp.databases.ConnectionBean" scope="session"/> <% String showID = request.getParameter("show"); connection.setAutoCommit(false); String sql; sql = "UPDATE conference set assentos=assentos-1 where id=" + showID; connection.executeUpdate(sql); %> <html> <body> <center> <font size="+2" face="arial"><b>Reservar Ponte Aérea</b></font> <form action="confirm.jsp" method="post"> <table border=1 bgcolor="tan" width="50%" align="center"> <tr><td> <table border="0" bgcolor="white" cellspacing=0 width="100%"> <tr bgcolor="tan"><th> </th> <th>Aeroporto</th><th>Hora</th><th>Lugares Vagos</th></tr> Exemplo Prático shuttle.jsp (parte 2 de 2) <tr> <% sql = "SELECT s.* from shuttles s, conference c where c.id=" + showID + " and s.aeroporto = c.aeroporto"; ResultSet results = connection.executeQuery(sql); while (results.next()) { if (results.getInt("assentos") > 0) { %> <td> <input type="radio" name="shuttle" value="<%= results.getString("id") %>"> </td> <% } else { %> <td> </td> <% } %> <td><%= results.getString("aeroporto") %></td> <td><%= results.getTime("hora") %></td> <td align="center"><%= results.getString("assentos") %></td> </tr> <% } %> </table> </td></tr></table> <input type="hidden" name="show" value="<%= showID %>"> <input type="submit" value="Proximo (Revisar Reservas)"> </form> </center></body></html> Exemplo Prático confirm.jsp (parte 1 de 2) <%@ page import="java.sql.*" errorPage="error.jsp" %> <jsp:useBean id="connection" class="com.taglib.wdjsp.databases.ConnectionBean" scope="session"/> <% String sql; String shuttleID = request.getParameter("shuttle"); String showID = request.getParameter("show"); sql = "UPDATE shuttles set assentos=assentos-1 where id=" + shuttleID; connection.executeUpdate(sql); sql = "SELECT c.cidade, c.aeroporto, s.hora from conference c, " + "shuttles s where c.id=" + showID + " and s.id=" + shuttleID; ResultSet results = connection.executeQuery(sql); results.next(); %> <html><body><center> <font size="+2" face="arial"><B>Confirmação de Reservas</b></font> <form action="finish.jsp" method=post> <table border=1 bgcolor="tan" width="50%" align="center"> <tr><td> Exemplo Prático confirm.jsp (parte 2 de 2) <table border="0" bgcolor="white" cellspacing=0 width="100%"> <tr bgcolor="tan"><th>Resumo</th></tr> <tr><td> Reserva requisitada para a conferência na cidade de <b><%= results.getString("cidade") %></b>, com ponte aérea partindo do aeroporto de <b><%= results.getString("aeroporto") %></b> às <b><%= results.getTime("hora") %></b>. <p> Para confirmar suas reservas, selecione Confirmar Reservas. </td></tr> </table> </td></tr></table> <p> <input type="submit" name="commit" value="Confirmar Reservas"> <input type="submit" name="rollback" value="Cancelar Reservas"> </body> </html> Exemplo Prático finish.jsp <%@ page import="java.sql.*,com.taglib.wdjsp.databases.*" errorPage="error.jsp" %> <html><body> <% ConnectionBean connection = (ConnectionBean)session.getAttribute("connection"); if (request.getParameter("commit") != null) connection.commit(); else connection.rollback(); session.removeAttribute("connection"); %> <center> <% if (request.getParameter("commit") != null) { %> <font size="+2" face="arial"><b>Confirmação de Reservas</b></font> <p> Sua reserva foi confirmada, obrigado... <% } else { %> <font size="+2" face="arial"><b>Cancelamento de Reservas</b></font> <p> Suas reservas foram canceladas. <% } %> <a href="conference.jsp">Outra Reserva</a> </body></html> Exemplo Prático error.jsp <%@ page import="java.sql.*,com.taglib.wdjsp.databases.*" isErrorPage="true" %> <html> <body> <% if (exception instanceof SQLException) { try { ConnectionBean connection = (ConnectionBean)session.getAttribute("connection"); connection.getConnection().rollback(); session.removeAttribute("connection"); } catch (SQLException e) { } } %> <center> <font size="+2" face="arial"><b>Erro na Aplicaçã</b></font> <p> Um erro ocorreu: <tt><%= exception %></tt> <p> <a href="conference.jsp">Outra Reserva</a> </center></body></html> Boa Noite!