Programação iii   volume 3 v23
Upcoming SlideShare
Loading in...5
×
 

Like this? Share it with your network

Share

Programação iii volume 3 v23

on

  • 1,450 views

Apostila de Programação III. Direito sobre o conteúdo reservado aos autores da apostila.

Apostila de Programação III. Direito sobre o conteúdo reservado aos autores da apostila.

Statistics

Views

Total Views
1,450
Views on SlideShare
1,450
Embed Views
0

Actions

Likes
0
Downloads
58
Comments
1

0 Embeds 0

No embeds

Accessibility

Categories

Upload Details

Uploaded via as Adobe PDF

Usage Rights

© All Rights Reserved

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
    Processing…
Post Comment
Edit your comment

Programação iii volume 3 v23 Document Transcript

  • 1. UNIVERSIDADE FEDERAL RURAL DE PERNAMBUCO (UFRPE) COORDENAÇÃO GERAL DE EDUCAÇÃO A DISTÂNCIA (EAD/UFRPE) Programação III Fernando Antonio Mota Trinta Volume 3 Recife, 2011
  • 2. Universidade Federal Rural de PernambucoReitor: Prof. Valmar Corrêa de AndradeVice-Reitor: Prof. Reginaldo BarrosPró-Reitor de Administração: Prof. Francisco Fernando Ramos CarvalhoPró-Reitor de Atividades de Extensão: Prof. Delson LaranjeiraPró-Reitora de Ensino de Graduação: Profª. Maria José de SenaPró-Reitora de Pesquisa e Pós-Graduação: Profª Antonia Sherlânea Chaves VérasPró-Reitor de Planejamento: Prof. Romildo Morant de HolandaPró-Reitor de Gestão Estudantil: Prof. Valberes Bernardo do NascimentoCoordenação Geral de Ensino a Distância: Profª Marizete Silva SantosProdução Gráfica e EditorialCapa e Editoração: Rafael Lira, Italo Amorim e Everton FelixRevisão Ortográfica: Elias VieiraIlustrações: Allyson Vila NovaCoordenação de Produção: Marizete Silva Santos
  • 3. Sumário Apresentação................................................................................................................. 5 Conhecendo o Volume 3 ................................................................................................ 6 Capítulo 1 – Uma visão geral sobre bancos de dados...................................................... 8 1. Introdução ...................................................................................................................8 2. Por que os Bancos de Dados existem? ........................................................................9 3. Arquitetura Geral de um SGBD ..................................................................................12 3.1 Banco de Dados e uma visão em camadas ........................................................13 4. A modelagem e a representação de dados em um SGBD .........................................14 4.1 O Modelo Relacional ..........................................................................................15 4.2 Um modelo relacional para o sistema bancário.................................................17 Capítulo 2 – A linguagem estruturada de consulta: SQL ................................................ 23 1. Introdução .................................................................................................................23 2. Classificação de comandos SQL .................................................................................24 3. Instalação e utilização do HyperSQL ..........................................................................25 4. Comandos DDL ..........................................................................................................27 4.1 Criando tabelas ..................................................................................................27 4.2 Alterando tabelas ...............................................................................................31 4.3 Apagando tabelas ..............................................................................................31 5. Comandos DML e DQL ...............................................................................................32 5.1 Inserindo dados em tabelas ...............................................................................32 5.2 Visualizando dados das tabelas..........................................................................35 5.3 Alterando dados em tabelas ..............................................................................41 5.4 Removendo registros ........................................................................................42
  • 4. Capítulo 3 – A especificação JDBC ................................................................................ 47 1. Introdução .................................................................................................................47 2. JDBC ...........................................................................................................................48 3. Configurando eclipse para usar JDBC ........................................................................50 4. Utilizando a API JDBC .................................................................................................55 4.1 Estabelecendo uma conexão com o banco ........................................................55 4.2 Acessando o banco de dados .............................................................................56 4.3 Parametrizando consultas ..................................................................................61 5. Transações com JDBC ................................................................................................63 6. Integrando o Banco com o Sistema de Contas ..........................................................64Conheça o Autor .......................................................................................................... 76
  • 5. Apresentação Caro Cursista, Seja bem-vindo(a) ao curso de Programação III. Esta disciplina dará seqüência aos estudos iniciadosna disciplina de linguagem de programação II, apresentando conceitos avançados relacionados à construçãode aplicações orientadas a objetos. Este curso é composto por 4 volumes. No primeiro volume, estudamos aimportância da boa organização dos sistemas, por meio dos conceitos de arquitetura de software e padrões deprojeto. Em seguida, vimos como podemos criar aplicações multitarefa utilizando threads de threads, para, por fim,aprendermos a gerenciar arquivos em aplicações orientadas a objetos. O segundo volume foi dedicado ao estudo do conceito de frameworks e à construção da interface do usuário,utilizando recursos avançados como janelas, botões, listas de seleção, e outras metáforas bastante conhecidas dasaplicações modernas. Este assunto aborda ainda o chamado modelo de programação orientado a eventos. Este terceiro volume é totalmente dedicado ao estudo da integração de aplicações com bancos de dados.Para isto, veremos primeiramente conceitos fundamentais sobre bancos de dados, para depois vermos como se dásua integração com aplicações. No quarto e último volume, você aprenderá a criar aplicações distribuídas utilizando duas abordagens: ade sockets e a de objetos distribuídos. Em todos estes volumes, re-utilizaremos conceitos aprendidos no curso delinguagem de programação II, e sempre que possível, utilizaremos o estudo de caso desenvolvido anteriormente, osistema de controle bancário, para apresentar os novos conceitos de cada capítulo. Portanto, é de fundamental importância que você tenha bem sedimentado os conceitos de orientaçãoa objetos para dar prosseguimento a esta disciplina. No mais, espero que você aproveite este material paraaprofundar-se ainda mais sobre como deve-se construir aplicações mais robustas e próximas de cenários reais dodesenvolvimento de software na atualidade. Bons estudos! Professor Fernando Trinta 5
  • 6. Programação III Conhecendo o Volume 3 Neste terceiro volume, você irá encontrar o Módulo 3 da disciplina Programação III. Para facilitar seus estudos, veja a organização deste terceiro módulo. Módulo 3 – Uma introdução à integração de programas com bancos de dados Carga Horária do Módulo 3: 15 h Objetivo do Módulo 3: Introduzir os conceitos básicos de bancos de dados, sua organização interna de dados e relação com o mundo orientado a objetos. Apresentar a linguagem SQL para manipulação de dados. Apresentar a especificação JDBC para conexão de programas escritos em linguagem Java com bancos de dados. Conteúdo Programático do Módulo 3 » Introdução a bancos de dados; » A Linguagem SQL; » A Especificação JDBC. Como relatado anteriormente, o terceiro volume desta disciplina é totalmente dedicado à integração de programas como bancos de dados. Este é um assunto muito importante. Praticamente todo sistema de informação é composto por programas que interagem com bases de dados que são gerenciadas por um software específico, o sistema gerenciador de bancos de dados ou SGBD. A importância da manutenção correta destes dados é tanta, que esta é considerada uma área de pesquisa específica dentro da ciência da computação, com disciplinas inteiras dedicadas a conceitos específicos e a forma correta de se definir e manipular bancos de dados. Não é objetivo desta disciplina abordar todos os conceitos relacionados à área de bancos de dados. Para isto, existem dentro do curso disciplinas específicas para tal. Esta é uma disciplina que busca abordar como se dá a integração entre o mundo do das aplicações escritas em linguagens de programação orientadas a objetos e o mundo dos bancos de dados. Desta forma, este volume apresenta apenas um subconjunto dos conceitos mais relevantes de bancos de dados, e que são necessários para integração entre um programa escrito em Java e uma base de dados. Posso afirmar então que esta é uma disciplina com viés prático. Você verá no primeiro capítulo, conceitos básicos sobre bancos de dados, enfatizando sua evolução histórica e principalmente, como se dá a organização interna de um banco de dados. O segundo capítulo é dedicado à linguagem SQL. Esta é a linguagem padrão para manipulação de dados em um SGBD. No terceiro e último capítulo é apresentado o Java Database Connectivity, ou simplesmente JDBC, a especificação padrão para integração entre programas orientados a objetos escritos em Java e uma gama de bancos de dados disponibilizados pela indústria.6
  • 7. Programação III Capítulo 1 O que vamos estudar neste capítulo? Neste capítulo, vamos estudar o seguinte tema:» Introdução a bancos de dados. Metas Após o estudo deste capítulo, esperamos que você consiga:» Aprender os conceitos relacionados com bancos de dados e suas diferenças em relação ao mundo orientado a objetos. 7
  • 8. Programação III Capítulo 1 – Uma visão geral sobre bancos de dados Vamos conversar sobre o assunto? Caro cursista, A importância da informática é evidente pela dependência que a sociedade contemporânea tem dos sistemas de informação (SI). Independente de seus diferentes propósitos, estas aplicações tem como característica comum a manipulação de dados de diversas formas, números e texto até conteúdo multimídia, como imagens e vídeos. Gerenciar tais dados de forma eficiente é de fundamental importância para qualquer instituição. Portanto, entender como os dados de uma aplicação devem ser representados e como interagir com tais dados é também importante para qualquer desenvolvedor de aplicações. Por conta disso, neste capítulo, vamos estudar os conceitos básicos necessários para entender a importância e o funcionamento dos bancos de dados. 1. Introdução Um Banco de Dados (também chamado de Base de Dados) é uma coleção de dados relacionados, organizados e armazenados visando facilitar a manipulação dos dados armazenados, permitindo realizar alterações, inserções, remoções e consultas. Neste contexto, um “dado” representa um elemento que mantém a sua forma bruta (texto, imagens, sons, vídeos, etc.) e que sozinho não levará a compreender determinada situação. Já “Informação” é o conjunto de dados coletados de forma a se tornarem aplicáveis a determinada situação, ou seja, sua forma e conteúdo são apropriados para um uso específico. A informação não existe por si só, ela é obtida através de uma interpretação realizada sobre um grupo de dados. Por exemplo, em um sistema acadêmico os dados representam as notas individuais de cada aluno, assim como seus nomes, idades, dentre outros. Destes dados pode-se extrair como informação o fato que os alunos de uma turma específica tiveram notas inferiores à média das demais turmas, e que portanto, precisam de uma atenção maior por parte da coordenação da escola. Em nosso cotidiano, existem várias bases de dados com as quais interagimos diariamente. Verificar o saldo bancário de uma conta, consultar livros no sistema da biblioteca, fazer a matrícula em um curso na universidade; em todos estes casos temos exemplos de aplicações que manipulam dados como contatos, livros ou dados pessoais. Para facilitar a interação das aplicações com estes dados, uma categoria especial de aplicações foi desenvolvida ao longo dos anos, os chamados Sistemas Gerenciadores de Bancos de Dados (SGBDs ou DBMS – Database Management System). Estes pacotes de software foram desenvolvidos com funções específicas para manipular dados, com operações pré-definidas para inserção, remoção, atualização e consulta dos dados armazenados. Neste capítulo vamos estudar os conceitos fundamentais sobre bancos de dados,8
  • 9. Programação IIIdesde a motivação para sua existência, passando por a arquitetura geral destes sistemas,chegando até a forma mais comum para representação dos dados, o modelo relacionalbaseado em tabelas.2. Por que os Bancos de Dados existem? No capítulo 3 do primeiro volume desta disciplina, vimos que é possível armazenardados em arquivos, permitindo que estas informação sejam salvas entre sessões de uso dasaplicações. Historicamente, esta foi a primeira forma pela qual aplicações gerenciaram seusdados, onde cada aplicação definia a forma específica como seus dados eram manipulados.Se mais de um programa desejasse utilizar os dados definidos em uma aplicação, todosos programas precisavam também compartilhar a estrutura de como tais dados eramarmazenados. Com a popularização dos sistemas de informação, as empresas começaram aenfrentar problemas relacionados à esta forma de gerenciamento. Se um determinadosistema precisasse realizar alguma mudança na estrutura de dados, todos os demais sistemasque acessassem os dados tinham que ser alterados, mesmo que a alteração ocorresse emdados não manipulados pelos outros programas. Em outra situação, se os sistemas distintosde uma mesma empresa utilizassem os mesmos dados, porém representados de formadistinta por cada sistema, estes dados precisavam ser replicados em cada sistema. Estareplicação trazia uma série de consequências negativas, dentre as quais pode-se destacar: » Alta possibilidade de inconsistência de dados replicados: Caso um dado replicado fosse atualizado em uma aplicação, o mesmo deveria ser atualizado em todos os demais sistemas. Caso contrário, um mesmo dado apresentaria valores distintos para a empresa, ocasionando inconsistência de informações. Por exemplo: Uma empresa que tivesse dois sistemas, um de controle de pessoal e outro financeiro precisaria manter informações replicadas sobre seus funcionários. Se o endereço de um funcionário fosse atualizado em um sistema, precisaria também ser atualizado no outro; » Maior custo de armazenamento: Os mesmos dados seriam armazenados diversas vezes, o que além de ocupar mais recursos, levaria a procedimentos extras para replicar as atualizações sobre os dados. No mesmo exemplo anterior, se houvessem mais sistemas que necessitassem das informações de um funcionário, os dados precisariam ser replicados para cada sistema. Com o passar dos anos e o aumento da importância dos sistemas de informação etambém de sua complexidade, buscou-se uma solução para tais problemas. O cenário vividoentão à época motivou à criação de um modelo onde dados fossem isolados de aplicações.Os dados, então representados por arquivos, seriam responsáveis unicamente por guardaras informações que fossem manipuladas pelos programas dos sistemas, representandoassim a própria base de dados (BD). Todo acesso ao BD passa a ser realizado de formacentralizada e unificada por um sistema intermediário, o Sistema Gerenciador de Banco deDados - SGBD. O SGBD funciona como um sistema intermediário, que atua como ponte entre cadaaplicação e a base de dados representada pelos arquivos onde os dados são persistidosfisicamente, como visto na Figura 1. 9
  • 10. Programação III Figura 1 – A visão de um SGBD como intermediário entre aplicações e dados Dentre as vantagens desta abordagem tem-se: » O acesso e manipulação de dados entre diferentes sistemas passa a ser feito de uma forma padronizada, que pode ser então compartilhadas entre várias aplicações; » Diferentes sistemas podem compartilhar os mesmos dados, delegando ao SGBD a intermediação de acesso entre aplicações e dados; » Os sistemas passariam a enxergar apenas os dados que lhes interessam, criando a idéia de visões. Por exemplo, se um banco de dados guarda todas as informações de um determinado funcionário, como dados pessoais, salário, cargo, dentre outras, um SGBD pode definir que uma determinada aplicação só consiga enxergar uma parte destes dados; » Os sistemas não precisariam conhecer os detalhes de como seus dados estão gravados fisicamente; » Os sistemas não precisariam ser modificados se a estrutura de dados que utilizam não for modificada; » Funcionalidades importantes como auditoria, cópias de segurança (backups) e segurança de acesso podem ser centralizadas e delegadas aos SGBD, abstraindo tais questões para as aplicações que utilizam os dados. Com tais vantagens, o uso de sistemas gerenciadores de bancos de dados foi rapidamente aceito e se tornou um padrão na indústria. Hoje é difícil imaginar um sistema comercial que não faça uso de SGBDs. Com o passar dos anos e a evolução de tais sistemas, o SGBD passou de programas simples para complexos sistemas de programas com função de habilitar desenvolvedores a criar e manter um banco de dados. Dentre suas funções principais estão: » Definição do banco de dados: Envolve especificar estruturas e tipos de dados para serem gravados no banco de dados, com uma descrição detalhada de cada tipo de dado. » Construção do banco de dados: Processo de consistir e gravar inicialmente dados no banco de dados. » Manipulação de um banco de dados: Inclui funções como consulta por dados específicos e atualização para refletir as alterações no mundo real. Hoje existem vários bancos de dados disponíveis no mercado, que possuem um núcleo comum de funcionalidades, mas variam em relação ao suporte a quantidade de usuários simultâneos, funcionalidades extras, eficiência e robustez. Obviamente, de acordo com estes critérios, um SGBD pode custar até centenas de milhares de dólares. Porém, é possível encontrar ótimas opções gratuitas disponíveis na Internet para serem utilizadas como SGBDs. Alguns dos principais SGBDs disponíveis no mercado nos últimos anos são: » Oracle - Sistema comercial, mas possui versões gratuitas para uso acadêmico e/10
  • 11. Programação III ou doméstico (em casa). Ele foi o primeiro Banco de Dados Corporativo (cliente/ servidor) possuindo grande variedade de distribuições (para Macintosh, Windows, Linux, FreeBSD, Unix) e para computadores de grande porte. Foi um dos primeiros a fazer parte do mercado Web. A participação do Oracle no mercado de Banco de Dados é bastante acentuada, principalmente em grandes empresas e em conjunto com sistemas de médio e grande porte. É um SGBD robusto e seguro, quando bem administrado. A Oracle também desenvolve uma suíte de desenvolvimento chamada de Oracle Developer Suite, utilizada na construção de programas de computador que interagem com a sua base de dados. Site Oficial em http://www. oracle.com/us/products/database/index.htm » Microsoft SQL Server – é o banco de dados comercial da Microsoft. Ele é um dos principais concorrentes do Oracle. Tem como uma das vantagens o fato de, por ser um produto Microsoft, se integrar nativamente com produtos e linguagens da Microsoft (talvez seja esse o fator que o popularizou!). As versões atuais são independentes e operam exclusivamente sobre Windows. É um software proprietário e pago, como a maioria dos produtos Microsoft. Algumas empresas que usam o MS SQL Server e são consideradas casos de sucesso no Brasil são o Hipercard, o Banco Itaú e a ANEEL (vide: http://www.microsoft.com/brasil/ servidores/sql/default.mspx). Site Oficial em http://www.microsoft.com/ sqlserver/2008/en/us/ » MySQL - é, atualmente, um dos bancos de dados mais populares, com mais de 10 milhões de instalações pelo mundo. Ele possui versões para Windows, Solaris, Unix, FreeBSD, Linux e é gratuito para uso não-comercial. Algumas das empresas mais famosas que fazem uso deste banco estão: NASA, Banco Bradesco, Dataprev, HP, Nokia, Sony e Lufthansa. O MySQL é usado principalmente para desenvolvimento WEB como servidor de dados para comércio eletrônico. Passou a ser considerado um SGBD de verdade (com conceito de transação) a partir da versão 5. Site Oficial em http://www.mysql.com/ » PostgreSQL - é um sistema gerenciador de banco de dados objeto relacional (SGBDOR), desenvolvido como projeto de código aberto. Ele é um dos SGBDs (Sistema Gerenciador de Bancos de Dados) de código aberto mais avançados, é grautito e tem uma boa aceitação no mercado. Originalmente concebido para rodar em Linux, ele possui versões para Windows. É usando, principalmente, para comércio eletrônico juntamente com linguagem PHP. O PostgreSQL é um projeto open source coordenado pelo PostgreSQL Global Development Group. Site Oficial em http://www.postgresql.org/ » Microsoft Access: é um banco de dados da Microsoft para uso em micros desktops e não em servidores. Esta é a principal diferença dele para os demais bancos SGBD como o Oracle, SQL Server e MySQL, por exemplo. Contudo, ele tem sido muito usado em pequenas e médias empresas para armazenamento de dados em pequenas quantidades. Agora, o MS Access não é considerado um SGBD completo, por não possuir todas as características de um. Mas ele permite o desenvolvimento rápido de aplicações que envolvem tanto a modelagem e estrutura de dados como também a interface a ser utilizada pelos usuários. A linguagem de programação disponível no access é a Microsoft Visual Basic for Applications, igualmente a outros produtos da série Microsoft Office. Maiores informações em: http://office. microsoft. com/pt-br/access/default.aspx Dos SGBDs listados acima vale ressaltar que o SQL Server e o Oracle tem versõesgratuitas, porém limitadas. O PostgreSQL é open source e e o MS Access é pagos (sendo queo Access já vem em algumas versões do pacote Microsoft Office) e o MySQL é gratuito para 11
  • 12. Programação III desenvolvimento, mas pago para produção. A escolha de qual SGBD usar depende muito do projeto sendo desenvolvido e do quanto a empresa está disposta a investir para armazenamento dos seus dados. Um SGBD gratuito e muito popular nos dias de hoje é o PostGreSQL e vários sistemas de instituições públicas vêm adotando o mesmo. Já no mundo corporativo o Oracle tem sido um dos mais adotados, por ser um dos mais robustos. 3. Arquitetura Geral de um SGBD Apesar de existir vários SGBD’s, uma arquitetura genérica para estes sistemas é apresentada na literatura. Esta arquitetura apresenta os componentes citados na Figura 2. Figura 2 - Arquitetura Geral de um SGBD De acordo com esta arquitetura, os componentes funcionais de um sistema de banco de dados incluem: » Gerenciador de arquivos, que gerencia a alocação do espaço na armazenagem do disco e as estruturas de dados usadas para representar a informação armazenada no disco; » Gerenciador do banco de dados, que fornece a interface entre os dados de baixo nível armazenados no disco e os programas aplicativos e de consulta submetidos ao sistema; » Processador de consultas, que traduz os comandos numa linguagem de consulta para instruções de baixo nível que o gerenciador do banco de dados pode interpretar. Além disso, o processador de consultas tenta transformar uma requisição do usuário em uma forma compatível e mais eficiente com respeito ao banco de dados, encontrando uma boa estratégia para a executar a consulta; » Pré-compilador da DML (Data Manipulation Language), que converte comandos da DML embutidos em um aplicativo para chamadas de procedimento normal na linguagem hospedeira. DML é uma linguagem para manipular dados e será melhor vista no capítulo 2 deste volume. O pré-compilador precisa interagir com o12
  • 13. Programação III processador de consultas pra gerar o código apropriado; » Compilador da DDL (Data Definition Language), que converte comandos da DDL em um conjunto de tabelas contendo metadados ou “dados sobre dados”. DDL permite que a estrutura de um banco seja criado, e assim como DML, será melhor abordado no capítulo 2; Adicionalmente, diversas estruturas de dados são requeridas como parte daimplementação do sistema físico, incluindo: » Arquivos de dados, que armazenam o banco de dados propriamente dito; » Dicionário de dados, que armazena metadados sobre a estrutura do banco de dados. O dicionário de dados é usado com freqüência. Assim, deve-se dar grande ênfase no desenvolvimento de um bom projeto e implementação eficiente do dicionário; » Índices, que fornecem acesso rápido aos itens de dados guardando determinados valores.3.1 Banco de Dados e uma visão em camadas Uma outra forma de se enxergar a arquitetura de um banco de dados é por meiode uma visão em camadas. Nesta visão, um banco de dados é composto de três camadas,como descrito na figura abaixo. O nível físico ou nível interno é aquele que está mais próximo ao armazenamentofísico dos dados. Este nível físico é descrito por meio de um esquema interno que definecomo registros, campos e índices são representados, principalmente em relação à sequênciafísica dos dados. Já o nível lógico situa-se acima do físico e é responsável por descrever como dadossão representados e relacionamentos entre os próprios dados. Esta representação é maisabstrata que os nível físico. Pode-se dizer que esta visão possibilita representar os dadoscomo estes realmente são, sem restrições que um usuário possa ter para visualizá-los, porconta de uma linguagem de programação em particular. O nível do usuário é aquele em que os usuários possuem diferentes visões dosdados, onde muitas vezes não é necessário o acesso a todos os dados da base. Neste nívelestão os programadores e usuários finais das aplicações. 13
  • 14. Programação III 4. A modelagem e a representação de dados em um SGBD Pela arquitetura e visão em camadas de um banco de dados, é importante perceber que bancos de dados tem um modelo específico de como os dados são representados e armazenados. Os modelos de dados utilizados em bancos de dados correspondem a como dados, relacionamentos, suas restrições e seus significados são descritos. Existem diferentes classificações para os modelos de dados, de acordo com diferentes critérios de separação. A seguir, apresentam-se cinco modelos de representação dos dados. O modelo hierárquico foi a primeira proposta para a representação de dados, onde os dados são representados por uma estrutura de árvore semelhante àquelas estudadas na disciplina de estrutura de dados. Dados são acessados segundo um sequência hierárquica com uma navegação do topo (raiz) para as folhas (nós sem folhas) e da esquerda para a direita dentro de um mesmo nó ou registro. Figura 3 - Modelo Hierárquico de Dados Apesar de representar uma primeira tentativa na padronização da representação de dados, o modelo hierárquica sofreu críticas por necessitar replicar dados em virtude do modelo de árvore utilizado, o que também levava a desperdício de espaço de armazenamento e à possibilidade de inconsistência de dados. O modelo em rede, assim como o modelo hierárquico, utiliza apontadores entre os dados. Porém, as associações entre os dados não necessariamente segue um modelo de árvore top-down como anteriormente. Figura 4 - Modelo de dados em rede Na abordagem em rede não aparecem as anomalias de manutenção da base de dados que aparecem em modelos hierárquicos. Porém, a necessidade que o programador conheça as várias ligações existentes na base cria uma forte dependência da implementação. As consultas são complicadas pois o programador é forcado a pensar em termos de ligações14
  • 15. Programação IIIe, em como percorrê-las para obter as informações de que necessita. A independência dedados fica prejudicada, pois a criação ou eliminação de ligações implica em alteração dosprogramas. O modelo relacional utiliza a teoria dos conjuntos e álgebra relacional para definirdados em função de tabelas, e relacionamentos entre os campos que formam os dados decada tabela. Falaremos mais sobre o modelo relacional ao final deste capítulo. Figura 5 - Modelo Relacional de Dados O modelo objeto é aquele que procura utilizar os conceitos já conhecidos doparadigma orientado a objetos para representar as informações da base. Os dados sãorepresentados através de classes que apresentam dados membros. Campos são instânciasdestas classes. Figura 6 - Modelos de dados como objetos Os bancos de dados orientados a objetos tem como objetivo integrar a orientação aobjeto com as aptidões dos bancos de dados, disponibilizando mais abstração da estruturade dados do que os bancos de dados convencionais. Existem atualmente ainda poucosprodutos no mercado. De todos estes modelos, o relacional são os de maior sucesso comercial até hoje, eportanto, serão melhor estudados na próxima seção e servirão de base para os exemplos denosso volume.4.1 O Modelo Relacional Este modelo foi o primeiro modelo de dados efetivamente utilizado em aplicaçõescomerciais. Este foi apresentado em 1970 por Codd em seus estudos na IBM sobre a 15
  • 16. Programação III modelagem de dados. É o modelo que possui a base mais formal entre os modelos de dados, entretanto é o mais simples e com estrutura de dados mais uniforme. A estrutura fundamental do modelo relacional é a relação, mas conhecido como tabela. Na verdade, o modelo é composto por uma coleção de tabelas de nomes únicos. Cada relação ou tabela é constituída por uma ou mais colunas chamadas de atributos (campos) que são os tipos dos dados contidos na relação. O conjunto de valores passíveis de serem assumidos por um atributo será intitulado de domínio. Cada linha da relação é chamada de tupla (registro). O esquema de uma relação nada mais é do que os campos (colunas) existentes em uma relação ou tabela. Já a instância da relação consiste no conjunto de valores que cada atributo assume em um determinado instante. Na intersecção de uma linha com uma coluna encontra-se o dado. Para exemplificar tais conceitos, a figura abaixo apresenta uma tabela para representar a entidade funcionário, com os campos CPF, Nome, Idade e Salário. Nesta tabela, três registros são apresentados para representar os dados de três funcionários. Figura 7 – Exemplo de uma tabela em um SGBD relacional As relações não podem ser duplicadas (por exemplo, não podem existir dois estados de Pernambuco, no conjunto de estados brasileiros) e a ordem de entrada de dados no Banco de Dados não deverá ter qualquer importância para as relações, no que concerne ao seu tratamento. Diferentemente dos modelos que o precederam o modelo relacional não tem caminhos pré-definidos para se fazer acesso aos dados. Os relacionamentos entre as tabelas são feitos através do uso de valores de atributos. Para exemplificar este relacionamento, as relações funcionário e departamento representam as informações sobre funcionários e departamentos que são relacionados pelo campo depto. Este relacionamento permite identificar quais são os departamentos que cada funcionário trabalha. Figura 8 - Exemplo de relacionamento entre duas tabelas16
  • 17. Programação III Para trabalhar com tabelas, algumas restrições precisaram ser impostas para evitaraspectos indesejáveis, como: Repetição de informação, incapacidade de representar parteda informação e perda de informação. Essas restrições são: integridade referencial e chaves. Em relação as chaves, existem três principais tipos usadas em SGBDs relacionais:as chaves primárias, as chaves candidatas e as chaves estrangeiras. A chave estrangeira éaquela que consegue identificar de forma unívoca um registro. Por exemplo, os camposCPF e registro nas tabelas apresentadas anteriormente são exemplos campos que nãose repetem ( ou que não devem se repetir), e portanto, seriam chaves primárias de suasrespectivas tabelas. Em geral, toda tabela deve possuir uma chave primária. Chavesprimárias não podem ter valores nulos e tendem a ser mínimas. Chaves candidatas possuem a mesma característica que uma chave primária,mas que por questões funcionais não foram escolhidas como chave primária. Chavesestrangeiras são valores que correspondem a chaves primárias de outras tabelas ou atémesma da própria tabela, e que estabelecem relacionamentos entre entidades. Já a integridade referencial remete à garantia que haja integridade de dados,através dos relacionamentos entre entidades. Por exemplo, na relação entre funcionáriose departamentos há uma garantia que para um funcionário ser incluído na base, ele devereferenciar departamento válido. Ao mesmo tempo, um registro de um departamento nãopode ser excluído se algum registro de funcionário fizer menção a tal departamento.4.2 Um modelo relacional para o sistema bancário Para ilustrar um modelo relacional, vamos criar um modelo de tabelas paraarmazenar as informações do sistema bancário, utilizado como estudo de caso em nossadisciplina. Lembrando um pouco deste sistema, em nosso banco, correntistas possuem umaconta, que pode ser tanto uma conta convencional, uma conta especial ou uma poupança.O diagrama de classes abaixo mostra as principais entidades de nosso sistema. Figura 9 - Diagrama de Classes do sistema bancário Uma coisa importante é entender que o mundo OO é diferente do mundo debancos de dados relacionais. Enquanto o primeiro trabalha com objetos, polimorfismo,herança, o segundo é constituído de tabelas, chaves e restrições. Porém, alguns elementosconseguem ser relacionados, como atributos de objetos mapeados em campos de umatabela. Boa parte das classes de um diagrama de classes é diretamente mapeada em umatabela em um modelo relacional. Porém, outros conceitos precisam adaptações. Veja porexemplo, a relação de herança entre as classes Conta, ContaEspecial e Poupanca. Os dadosde um objeto Conta podem ser mapeados para uma tabela também chamada CONTA, ondeos atributos da classe sejam mapeados em campos na tabela. Em geral, os bancos possuem 17
  • 18. Programação III tipos semelhantes à maioria das linguagens de programação. Além disso, o campo numero pode ser marcado como uma chave primária, pois toda conta deve ter um número único que a identifica na base. Esta mesma abordagem poderia ser utilizada para mapear as classes ContaEspecial e Poupanca. Porém, isto acarretaria problemas para certas operações, como por exemplo, fazer uma consulta do saldo de uma conta, sem conhecimento de seu tipo. Seria necessário fazer consultas nas três tabelas, além de se replicar informações, o que dificultaria, por exemplo, a introdução ou remoção de campos. Para isto, pode-se utilizar a integridade referencial para melhorar a modelagem relacional de tabelas. A Figura 10 mostra uma outra abordagem. Figura 10 – Mapeando herança com integridade referencial e chaves estrangeiras18
  • 19. Programação III Nesta nova abordagem, os elementos comuns a todo tipo de campo sãorepresentadas na tabela CONTA. É introduzido um campo para identificar que tipo de contase trata um registro na tabela. As tabelas CONTA_ESPECIAL e POUPANCA fazem referenciaà tabela CONTA por meio de uma chave estrangeira que aponta para os dados comuns,enquanto armazenam informações específicas sobre seus tipos. Com isto, acaba-se areplicação de informações e centraliza-se as modificações no modelo de dados. Com a idéia das chaves estrangeiras também é possível mapear os relacionamentosexistentes entre as classes do modelo OO. Por exemplo, uma conta possui umrelacionamento um objeto Pessoa que representa o correntista da conta. O correntista porsua vez, possui dois relacionamentos com objetos do tipo Endereco, para representar osendereços comercial e residencial do correntista. A figura abaixo mostra o modelo para omapeamento das classes Pessoa e Conta. Neste caso, as tabelas PESSOA e ENDERECO devem representar os objetos Pessoae Endereco. Para criar os mapeamentos é necessário as chaves em cada tabela. Para atabela PESSOA, a chave primária é facilmente identificada. Cada pessoa é identificada porseu cpf, que é único para cada correntista. Porém, no caso do endereço, não há uma chaveexplícita. Neste caso, a solução é criar um campo que assuma a função de chave e sirvapara identificar cada registro da tabela. Nestas situações, por via de regra, este campo épreenchido automaticamente a cada inserção de um novo registro na tabela. Em certos casos, o simples relacionamento por meio de chaves estrangeiras não éviável para representar o mapeamento de classes. Veja por exemplo a situação descrita nodiagrama UML a seguir. 19
  • 20. Programação III Figura 11 – Diagrama de classes representando o relacionamento entre professores e disciplinas O diagrama busca representar a situação onde um professor pode lecionar várias disciplinas, e uma disciplina pode ser lecionada por diferentes professores. Nesta relação de M:N (muitos para muitos) a solução passa pela criação de uma tabela intermediária. Esta tabela cria mapeamentos de chave estrangeira para as tabelas que representam as duas classes. Desta forma, é possível representar este tipo de relacionamento de dados, como representado pela figura abaixo. Figura 12 - Mapeamento M:N no modelo relacional Neste exemplo, a tabela PROFESSOR_DISCIPLINA possui a chave primária composta pela união dos campos MATRICULA e CODIGO. O primeiro é chave estrangeira para a tabela PROFESSOR, enquanto o segundo é chave estrangeira para a tabela DISCIPLINA. Pelos dados do exemplo, o professor Fernando Trin ta (matrícula 1) leciona as disciplinas matemática (código 55) e física (código 100). Exercícios 1. Descreva as motivações para o surgimento de sistemas gerenciadores de bases de dados. Cite exemplos de seu dia a dia que utilizam bases de dados com muitos dados (milhares de registros). 2. Busque na Internet, bancos de dados que sigam os seguintes modelos de dados: (a) hierárquico, (b) em rede, (c) relacional e (d) orientado a objetos. 3. Utilizando o modelo de dados relacional, crie modelos para bancos de dados que precisem guardar informações sobre: a) Uma biblioteca que permita empréstimos de livros a seus usuários;20
  • 21. Programação III b) Um sistema acadêmico que represente alunos, professores e disciplinas; c) Uma loja de produtos eletrônicos. Vamos Revisar? Resumo Neste capítulo, você aprendeu conceitos básicos sobre bancos de dados, desde amotivação para seu surgimento, passando por sua arquitetura e os principais modelos derepresentação e organização de dados existentes na literatura. A maior importância destecapítulo é apresentar o modelo relacional, pois este é o modelo dominante das aplicaçõesmodernas. Entender como objetos são mapeados para tabelas é fundamental paraentender como sistemas escritos em linguagens orientadas a objetos podem persistir suasinformações em bases de dados relacionais. 21
  • 22. Programação III Capítulo 2 O que vamos estudar neste capítulo? Neste capítulo, vamos estudar o seguinte tema: » A Linguagem SQL de manipulação de dados. Metas Após o estudo deste capítulo, esperamos que você consiga: » Entender os principais comandos da linguagem SQL; » Aprender a utilizar um banco de dados simples chamado HyperSQL; » Realizar operações no HyperSQL com alguns dos principais comandos SQL.22
  • 23. Programação IIICapítulo 2 – A linguagem estruturadade consulta: SQL Vamos conversar sobre o assunto? Caro cursista, depois de estudar e ter uma visão geral sobre como os bancos dedados são organizados, é preciso então entender como os dados são manipulados porusuários e aplicações. Para isto, este capítulo é dedicado totalmente ao estudo da linguagemSQL, o padrão da indústria para a realização de operações em bases de dados relacionais.1. Introdução Em qualquer base de dados, uma questão importante é como são realizadas asoperações sobre os dados armazenados. Em geral, todo SGBD fornece uma linguagemde consulta por meio da qual usuários obtêm informações do banco de dados. Em geral,estas linguagens são de nível mais alto que as linguagens de programação tradicionais, esão categorizadas como procedurais ou não-procedurais (também referenciadas comodeclarativas). Em uma linguagem procedural, o usuário deve “ensinar” ao sistema arealização de uma seqüência de operações no banco de dados para obter o resultadodesejado. Em uma linguagem não-procedural, o usuário descreve a informação desejadasem fornecer um procedimento específico para a obtenção dessas informações. Nestecontexto, uma linguagem que precisa ser estudada para manipulação de SGBDs relacionaisé a linguagem SQL. SQL (Linguagem de Consulta Estruturada, do inglês Structure Query Language)é uma linguagem declarativa utilizada para manipulação de bases de dados relacionais,desenvolvida no início da década de 70 nos laboratórios da IBM, originalmente com o nomede SEQUEL (acrônimo para “Structured English Query Language” - Linguagem de ConsultaEstruturada em Inglês). O propósito da concepção de SEQUEL era demonstrar a viabilidadedo modelo relacional proposto por Codd. SQL O projeto de SEQUEL foi divulgado nos meios acadêmico por meio de conferênciase revistas especializadas, o que permitiu que seus conceitos pudessem ser implementadospor terceiros. No final da década de 70, duas outras companhias além da IBM iniciaramdesenvolvimento de produtos similares, que vieram a ser Oracle e Ingres. A OracleCorporation introduziu a primeira implementação de SQL comercialmente disponível, e éhoje líder no mercado de servidores de bancos de dados. A IBM também implementou SQLem seus sistemas de banco de dados DB2 e SQL/DS. Entre os anos 80 e 90, os produtoscom SQL se multiplicaram e hoje SQL é largamente implementada e aceita como o padrãode facto da indústria para linguagem de acesso a bancos de dados, desde sistemas desktopcomo o Microsoft Access para Windows até sistemas de gerenciamento e servidores debancos de dados de médio e grande porte em Unix, NT e mainframes. Hoje, SQL é padronizada por instituições normativas como a ANSI (Instituto 23
  • 24. Programação III Americo de Normas, do inglês American National Standards Institute) e ISO (Organização de Padrões Internacionais, do inglês International Standard Organization). Porém, certos fabricantes introduzem extensões e variações específicas a seus produtos, o que acaba por comprometer a portabilidade de programas que utilizem tais extensões para manipular SGBDs. No capítulo que segue, você aprenderá comandos básicos da linguagem SQL que serão necessários para a manipulação de dados em seus programas escritos em Java. Para que você veja na prática o uso destes comandos, você também aprenderá a manipular um SGBD simples chamado HyperSQL, que também será utilizado nos exemplos do próximo capítulo, quando finalmente virmos a integração de Java com este SGBD. 2. Classificação de comandos SQL SQL oferece uma série de comandos para realizar suas operações e tem como principais características a simplicidade e facilidade de uso. As operações em SQL podem tanto definir o modelo de dados da base, quanto inserir, alterar ou apagar registros. De forma a melhor organizar o conjunto completo de comandos, SQL classifica tais comandos em cinco grupos: » DDL (Linguagem de Definição de Dados, do inglês Data Definition Language): subconjunto que permite ao desenvolvedor definir tabelas novas e elementos associados. Fazem parte deste grupo os comandos CREATE, ALTER TABLE e DROP. » DML(Linguagem de manipulação de dados, do inglês Data Manipulation Language): subconjunto da linguagem da SQL que são utilizados para realizar inclusões, consultas, exclusões e alterações de dados presentes em registros. Incluem o comandos INSERT, UPDATE e DELETE. » DQL(Linguagem de consulta de dados, do inglês Data Query Language): formada por apenas um comando, é a parte mais utilizada de SQL. Por meio do comando SELECT, é possível realizar consultas dos mais diversos tipos, de acordo com cláusulas e opções que podem ser utilizadas no comando. » TCL(Linguagem de controle de transações, do inglês Transaction Control Language): Conjunto de operações utilizados para tratamento de transações. Uma transação é um conjunto de operações individuais que devem ser agrupadas e tratadas como uma só. Fazem parte desta classe os comandos START TRANSACTION, COMMIT e ROLLBACK. » DCL(Linguagem de controle de dados, do inglês Data Control Language): Este conjunto de comandos controla os aspectos de autorização de dados e permissões de usuários para controlar quem tem acesso para ver ou manipular dados dentro do banco de dados. Dois dos principais comandos são o GRANT e o REVOKE, que respectivamente concedem e retiram permissões de usuários. Em nossa disciplina, nós veremos principalmente os comandos DDL, DML e DQL. Para isto, os comandos serão apresentados no contexto da criação de um banco de dados para o sistema de controle bancário que nos acompanha desde a disciplina de linguagem de programação II. Para que podemos ver na prática o uso de SQL, utilizaremos um banco bem simples disponível na Internet chamado HyperSQL (http://hsqldb.org/). O HyperSQL é um SGBD relacional escrito em Java que implementa as funcionalidades básicas necessárias para nossos exemplos. Mas que isso, é um banco extremante portável, já que o seu executável ocupa menos que 2Mb.24
  • 25. Programação III3. Instalação e utilização do HyperSQL Para instalar e executar o HyperSQL é preciso ter a plataforma Java instalada ebaixar o aplicativo do site http://hsqldb.org/. Na sua distribuição, o HyperSQL é um arquivocompactado, que quando descompactado cria uma árvore de diretórios contendo scriptsde execução, documentação, exemplos, código-fonte do banco, dentre outros, comoapresentado na Figura abaixo. Figura 13 - Estrutura do HyperSQL, depois de descompactado Porém, apesar de todas essas informações, o único arquivo necessário paraexecutar o banco é o arquivo hsqldb.jar, localizado na pasta lib. Este arquivo representa obanco, assim como a interface de administração e o driver JDBC que será necessário paraintegrar os programas Java com o HyperSQL, a ser visto no próximo capítulo. O HyperSQL é um programa Java. Logo, para executá-lo basta usar o interpretadorjava para executar a aplicação, cuja classe principal é a org.hsqlbd.server.Server. Logo, aforma mais simples para isso é abrir uma janela para disparar o comando: java -cp .;<<caminho completo para o arquivo hsqldb.jar>> org.hsqlbd.server.Server Ao fazer isto, o processo é iniciado e são criados arquivos que representam osdados no diretório onde o interpretador Java foi chamado. Na própria estrutura definidana descompactação, já é sugerida a pasta Data para este fim. Logo, é sugerido que vocêexecute o processo dentro desta pasta, como apresentado na Figura abaixo. Figura 14 - Rastro de execução do HyperSQL 25
  • 26. Programação III Ao fazer isso, o processo fica em execução. Para finalizar a execução do processo, basta pressionar [CRTL] + [C]. Ao executar o banco na forma mais simples, o HyperSQL cria uma série de arquivos, padronizados pelo prefixo test, como visto na Figura. Figura 15 - Arquivos gerados na execução do HyperSQL Estes arquivos representam os dados da base. É possível armazenar mais de uma base, assim como criar arquivos com nomes específicos para cada banco. Tais informações podem ser obtidas na documentação do HyperSQL. Nos exemplos utilizados neste livro, utilizaremos o padrão fornecido para facilitar a didática. Uma vez o banco estando em execução, é necessário interagir com a base. Para isto, o HyperSQL fornece uma aplicação simples, baseada em uma janela Swing, que permite visualizar o conteúdo do banco, bem como executar comandos a partir de uma janela de interação. Esta aplicação também é fornecida com o arquivo hsqldb.jar, por meio da classe org.hsqldb.util.DatabaseManagerSwing. Logo para executá-la, basta disparar o comando: java -cp .;<<caminho completo para o arquivo hsqldb.jar>> org.hsqldb.util.DatabaseManagerSwing Este comando pode ser disparado de qualquer diretório e a figura abaixo apresenta a tela principal da aplicação. Figura 16 - Tela de Abertura da aplicação DatabaseManagerSwing26
  • 27. Programação III Na execução do aplicativo, é apresentada uma janela com uma série de opções paraconexão com o banco. Para a correta conexão, devem ser mantidas as opções apresentadasna Figura, e então pressionado o botão OK. Feito isso, você estará conectado ao Banco epronto para executar operações. Nas próximas seções, utilizaremos esta interface para verna práticas exemplos de vários comandos SQL.4. Comandos DDL Os primeiros comandos que precisam ser realizados para se manipular um banco dedados são aqueles que permitem a criação das tabelas, índices, chaves, e demais elementosque compõem a base de dados. São três os principais comandos DDL existentes em SQL: » CREATE: comando que permite que sejam criados as tabelas, seus campos, chaves, além dos relacionamentos entre tais elementos; » ALTER TABLE: comando que permite que sejam feitas alterações em elementos já existentes da base de dados; » DROP: comando que apaga um elemento da base de dados. Vamos começar a ver tais comandos e a criar nossa base de testes. Primeiramente,vamos criar a base.4.1 Criando tabelas Vamos começar pelo comando CREATE, que tem sua sintaxe simplificada daseguinte forma: CREATE <<NOME_TABELA> (<<CAMPO1>> <<TIPO_CAMPO1>> <<OPÇÕES_CAMPO1>>, <<CAMPO1>> <<TIPO_CAMPO1>> <<OPÇÕES_CAMPO1>>, ... <<CAMPON>> <<TIPO_CAMPON>> <<OPÇÕES_CAMPON>> FOREIGN KEY(<<CAMPO>>) REFERENCES <<TABELA>> (<<CAMPO_CHAVE>>) Nesta definição, dá-se um nome para uma tabela e em seguida faz-se a definição decada um de seus campos. Cada campo tem obrigatoriamente um nome e um tipo, além decláusulas a mais que definem se um campo é chave primária, se ele pode ou não ter valoresnulos. Em relação aos tipos, os bancos definem tipos primários para valores de seuscampos, da mesma forma que linguagens de programação definem seus tipos básicos.Embora SQL defina valores padrões para os principais de dados como inteiros, alfanuméricos,booleanos, dentre outros, é importante verificar a documentação da base de dados a serutilizada, para verificar os tipos definidos por tal SGBD. No caso do HyperSQL, os principais tipos que serão usados neste volume sãoapresentados na tabela a seguir: 27
  • 28. Programação III Tipo Descrição INTERGE Valores numéricos inteiros DOUBLE Valores numéricos de ponto flutuante VARCHAR (TAMANHO) Valores alfanuméricos com tamanho definido BOOLEAN Valores lógicos IDENTITY Valores inteiros pré-definidos em uma sequência Tabela 1 - Tipos de Dados do HyperSQL É possível observar que com exceção do tipo IDENTITY, os demais são equivalentes a tipos já vistos na linguagem Java, como int, double, String e boolean. O tipo IDENTITY é uma opção muito útil para definirmos uma chave primária de uma tabela cujo valor seja gerado automaticamente pelo próprio banco. Veremos mais sobre o tipo IDENTITY logo a seguir. Existem ainda opções que podem ser associadas a cada campo. Uma das principais opções é identificar se um determinado campo é a chave primária da tabela. Para isto, utiliza-se a expressão PRIMARY KEY associado ao campo que será a chave primária da tabela. Se for uma chave composta, cada campo da chave composta deve ser marcada com este atributo. Também é possível determinar se um campo pode ou não ter valores nulos em algum registro da tabela. Caso isso não seja permitido, pode-se adicionar à definição do campo a expressão NOT NULL. Para exemplificar, vamos utilizar o comando CREATE para criar a tabela Endereco do sistema de controle bancário. Para isto, utilizamos então o seguinte comando: CREATE TABLE ENDERECO (ID_ENDERECO IDENTITY PRIMARY KEY, RUA VARCHAR(255) NOT NULL, NUMERO VARCHAR(255) NOT NULL, BAIRRO VARCHAR(255) NOT NULL, CIDADE VARCHAR(255) NOT NULL, ESTADO VARCHAR(20) NOT NULL, CEP VARCHAR(8) NOT NULL) Neste comando, está sendo criada uma tabela chamada ENDERECO com 7 campos. Todos os campos, com exceção de ID_ENDERECO são alfanuméricos. O campo ESTADO pode ter valores com no máximo 20 caracteres, enquanto o campo CEP pode ter valores com no máximo 8 caracteres. Os demais podem ter o valor máximo de 255 caracteres. O campo ID_ENDERECO é definido como um IDENTITY. Além disso, este campo também é definido como chave primária da tabela, que será utilizado para o relacionamento com os correntistas. Lembrando: cada correntista possui dois endereços: um comercial e outro residencial. O número associado a cada registro de endereço será utilizado para efetuar esta relação. Para que o desenvolvedor não se preocupe com a geração dos valores deste campo, o tipo IDENTITY é utilizado. A figura abaixo mostra a execução do comando na aplicação de gerenciamento do HyperSQL.28
  • 29. Programação III Figura 17 – Execução do Comando CREATE no HyperSQL Para executar o comando basta digitá-lo, e depois pressionar o botão ‘Execute SQL’.Note que no painel esquerdo, após a realização do comando, a tabela ENDERECO é listada. Continuando a criação do nosso banco, é necessário criar a tabela PESSOA, queguardará os dados dos correntistas do banco. Esta tabela deve possuir os campos CPF, NOME,SEXO, além de chaves estrangeiras para a tabela endereço. Estas chaves representarão osendereços comercial e residencial de cada correntista. Para criar a tabela pessoa utiliza-seentão o comando CREATE da seguinte forma: CREATE TABLE PESSOA (CPF VARCHAR(11) PRIMARY KEY NOT NULL, NOME VARCHAR(255) NOT NULL, SEXO VARCHAR(1) NOT NULL, END_RESIDENCIAL INTEGER NOT NULL, END_COMERCIAL INTEGER NOT NULL, FOREIGN KEY(END_RESIDENCIAL) REFERENCES ENDERECO(ID_ENDERECO), FOREIGN KEY(END_COMERCIAL) REFERENCES ENDERECO(ID_ENDERECO)) Veja que cada campo utiliza a sintaxe já explicada anteriormente. O campo CPF é umcandidato natural a chave primária da tabela, uma vez que o CPF de uma pessoa nunca deveser igual ao de outra. A novidade é a definição de duas chaves estrangeiras pelos camposEND_RESIDENCIAL e END_COMERCIAL. Veja que inicialmente eles são definidos como doiscampos inteiros convencionais. Porém, nas duas últimas linhas, a cláusula FOREIGN KEY fazuma associação entre estes campos, e o campo ID_ENDERECO da tabela ENDERECO. Destaforma, esta associação indica que para serem válidos, os dois campos devem conter valoresválidos para o campo ID_ENDERECO da tabela ENDERECO. Esta regra será reforçada quandocomeçarmos a colocar dados nas tabelas. Porém, este mesmo tipo de raciocínio vale para acriação da tabela CONTA. Toda conta possui seu número e saldo. Mas além disso, precisa estar relacionada auma pessoa que represente o correntista da conta. Logo, é necessário também a definição 29
  • 30. Programação III de uma chave estrangeira para estabelecer este relacionamento. O comando apresentado a seguir cria a tabela PESSOA: CREATE TABLE CONTA (NUMERO INTEGER PRIMARY KEY NOT NULL, TIPO INTEGER NOT NULL, SALDO DOUBLE NOT NULL, CPF VARCHAR(11) NOT NULL, FOREIGN KEY(CPF) REFERENCES PESSOA(CPF)) Observe que o número da conta é utilizado como chave primária da tabela, pois não devem haver contas com o mesmo número. O campo CPF é definido e, por fim, definido como chave estrangeira relacionada com a tabela PESSOA. Note que existe um campo a mais na definição da tabela CONTA: o campo tipo. Lembre-se que uma conta pode ser uma conta normal, uma conta especial ou mesmo uma poupança. Logo é preciso determinar este tipo na tabela. Além disso, nos casos da conta especial e da poupança, é necessário ainda armazenar informações extras. Por isso, são definidas novas tabelas: CONTA_ESPECIAL e POUPANCA. Cada uma delas possui uma relação com a tabela CONTA por meio de uma chave estrangeira, e suas definições são apresentadas a seguir: CREATE TABLE CONTA_ESPECIAL (NUMERO INTEGER PRIMARY KEY NOT NULL, LIMITE FLOAT NOT NULL, FOREIGN KEY(NUMERO) REFERENCES CONTA(NUMERO)) CREATE TABLE POUPANCA (NUMERO INTEGER PRIMARY KEY NOT NULL, DIA_ANIVERSARIO INTEGER NOT NULL, TAXA_JUROS DOUBLE NOT NULL, FOREIGN KEY(NUMERO) REFERENCES CONTA(NUMERO)) A Figura abaixo mostra o banco de dados, após todas a tabelas terem sido criadas. Figura 18 - Visão do SGBD após criação das tabelas30
  • 31. Programação III Percebe-se que existe uma ordem natural na criação das tabelas no banco. Primeiro,deve-se criar sem nenhum tipo de dependência com outras tabelas, para então se partirpara aquelas com maior número de referências a outras tabelas do banco.4.2 Alterando tabelas Uma vez criada uma tabela, é possível fazer modificações na estrutura da mesma.Tais ações são fundamentais para alterações em bancos de dados que sofram modificaçõespara atender novos requisitos, como surgimento de novos campos ou novos relacionamentoscom outras tabelas. Para isto, utiliza-se o comando ALTER TABLE, cuja sintaxes básicas sãoapresentadas a seguir: ALTER TABLE <<TABELA>> {ADD COLUMN <<CAMPO>> <<TIPO>> <<OPÇÕES>>} {ADD FOREIGN KEY<<CAMPO>> REFERENCES <<TABELA(CAMPO)>>} {DROP COLUMN <<CAMPO>>} {ALTER COLUMN <<CAMPO>> RENAME TO <<NOVO_NOME_CAMPO>>} ou ALTER TABLE <<TABELA>> RENAME TO <<NOVO_NOME_TABELA>> Seguem alguns exemplos do uso do comando ALTER TABLE: » Para adicionar um campo ESCOLARIDADE na tabela pessoa, utiliza-se o comando: ALTER TABLE PESSOA ADD COLUMN ESCOLARIDADE VARCHAR NOT NULL » Para remover o campo criado: ALTER TABLE PESSOA DROP COLUMN ESCOLARIDADE » Para mudar o nome do campo END_COMERCIAL para ENDERECO_COMERCIAL na tabela PESSOA: ALTER TABLE PESSOA ALTER COLUMN END_COMERCIAL RENAME TO ENDERECO_COMERCIAL O comando ALTER TABLE permite fazer outras mudanças nas tabelas, como mudaro tipo de um campo ou seu tamanho, que porém nesta disciplina não serão abordados.Uma coisa importante é que fazer alterações em tabelas que não possuam dados é muitomenos restritivo que naquelas que já possuem informações. Por exemplo, se quiséssemoscriar uma campo com a restrição NOT NULL em uma tabela que já possua 10 registros, issonão seria possível, pois ao criar o campo, todo registro possuiria um campo sem nenhumvalor. Neste caso, a solução seria primeiro criar o campo, depois atribuir valores para cadaregistro existente, para só então aplicar a restrição sobre valores nulos.4.3 Apagando tabelas Por fim, o último comando DDL é o DROP. Este comando permite apagar uma tabelada base de dados, e sua sintaxe é bem sucinta: DROP TABLE <<TABELA>> É importante observar que apesar de sua simplicidade, existem ressalvas ao seapagar uma tabela. Por exemplo, se você tentar apagar a tabela CONTA do banco de dados 31
  • 32. Programação III obterá uma mensagem de erro, como demonstrado abaixo. Figura 19 - Erro ao se apagar uma tabela que possui referências a outras tabelas A razão para este erro são os relacionamentos que uma tabela pode ter com outras tabelas, que impossibilitam que a mesma seja removida do banco. No nosso caso, as tabelas CONTA_ESPECIAL e POUPANCA referenciam a tabela CONTA, ou seja, são dependentes de informações contidas nesta última tabela. Portanto, a tabela CONTA não pode ser removida sem que antes, tais relacionamentos sejam desfeitos. No caso, ou as relações são desfeitas, ou as tabelas CONTA_ESPECIAL e POUPANCA são removidas primeiramente. 5. Comandos DML e DQL Uma vez a base criada, o banco se vê pronto para receber dados em cada tabela. Em SQL as instruções DML (Data Manipulation Language) são usadas para manipulação de dados e consiste nas operações de inserir dados (insert into), alterar dados (update) e excluir dados (delete), e são consideradas operações essenciais e de grande aplicação nas operações com banco de dados. Já o único comando DQL é o SELECT, que é utilizado para retornar os resultados de consultas. Estes comandos serão apresentados em conjunto para que a medida que dados sejam alterados, tais modificações possam ser visualizadas. Vamos ver cada um deles a seguir. 5.1 Inserindo dados em tabelas Vamos começar com o comando INSERT INTO, cuja sintaxe é apresentada abaixo: INSERT INTO <<TABELA>> [( <<COLUNA1>>, <<COLUNA2>>,...,<<COLUNA_N>>] ) ] { VALUES(<<VALOR1>>, << VALOR 2>>,...,<< VALOR _N>>)} O comando insert into permite que sejam criados registros em uma tabela. De acordo com esta sintaxe, um exemplo para inserção de dados na tabela ENDERECO seria como descrito a seguir. INSERT INTO ENDERECO(RUA, NUMERO, BAIRRO, CIDADE, ESTADO, CEP) VALUES(‘Avenida Recife’,’213’,’Boa Viagem’, ‘Recife’, ‘Pernambuco’, ‘51020021’);32
  • 33. Programação III Note que há uma correspondência entre cada campo e seu respectivo valor, e queos valores alfanuméricos são delimitados por aspas simples. No caso específico da tabelaENDERECO, você deve se lembrar que existe o campo ID_ENDERECO, definido como do tipoidentidade e que também é a chave primária da tabela. Relembrando, o valor deste campoé determinado pelo próprio banco de dados como uma sequência de valores inteiros quecomeça com 0 (zero) e que a cada novo registro é adicionado uma unidade. Ao executar este comando no HyperSQL, obtém-se como resultado o número deregistros afetados pelo comando. Neste caso, o valor obtido é 1(um), como ilustrado aseguir. Figura 20 - Comando Insert no HyperSQL Um detalhe importante na inserção de dados é a atenção em relação asdependências entre as tabelas. Por exemplo, para inserir dados na tabela PESSOA, sãonecessárias informações dos endereços comercial e residencial de cada correntista. Logo, énecessário que estas informações estejam previamente cadastradas. Tome como exemplo,o cadastro de uma pessoa com os seguintes dados: Dados Valor Nome Fernando Trinta CPF 111111111-11 Sexo Masculino Endereço Residencial Avenida Recife, 213, Boa Viagem, Recife – Pernambuco, CEP: 51020021 Endereço Comercial Avenida Caxangá, 23, Cordeiro, Recife – Pernambuco, CEP: 51040031 O endereço residencial já foi cadastrado anteriormente. Mas para cadastrar apessoa, é necessário cadastrar seu endereço comercial. Logo, primeiro tem-se que executaro seguinte comando: INSERT INTO ENDERECO(RUA, NUMERO, BAIRRO, CIDADE, ESTADO, CEP) VALUES(‘Avenida Caxangá’,’23’,’Cordeiro’, ‘Recife’,’Pernambuco’, ‘51040031’); Assume-se que ao criar este segundo endereço, o valor de seu campo ID_ENDERECO será igual a 1 (um), pois o primeiro registro iniciou com 0 (zero). Agora com osdois endereços cadastrados, é possível cadastrar o registro da pessoa na tabela PESSOA. 33
  • 34. Programação III INSERT INTO PESSOA(CPF, NOME, SEXO, END_RESIDENCIAL, END_COMERCIAL) VALUES(‘11111111111’,’Fernando Trinta’, ‘M’, 0, 1) Se por acaso, ao tentar incluir uma pessoa, se utiliza-se um valor para os endereços que não fosse válido, ou seja, inexistente, a operação seria invalidada. Veja por exemplo, o que acontece ao tentar inserir o registro passando o valor 3 para END_COMERCIAL. Figura 21 - Erro ao inserir um registro sem as devidas dependências satisfeitas Isso atesta o fato que é necessário ter atenção em se manter as relações de integridade referencial entre as tabelas. Por exemplo, para inserir um registro na tabela CONTA, é necessária a informação sobre o correntista. No caso, é necessário o CPF de uma pessoa cadastrada na tabela PESSOA. O comando abaixo cria um registro de uma conta cujo correntista é a pessoa de CPF igual a 11111111111, com número da conta igual a 1 e saldo de R$ 1000,00. INSERT INTO CONTA(NUMERO, SALDO, TIPO, CPF) VALUES (1, 1000, 1, ‘11111111111’); Em relação ao campo tipo, o valor estabelecido é determinado pelo desenvolvedor. No caso desta base de dados, será utilizada a seguinte tabela: Tipo da Conta Valor do Campo Tipo Normal 0 Especial 1 Poupança 2 Logo, a conta criada anteriormente é uma conta especial. Sendo uma conta especial, é necessário também inserir informações na tabela CONTA_ESPECIAL, como por exemplo, com o comando a seguir. INSERT INTO CONTA_ESPECIAL(NUMERO, LIMITE) VALUES(1, 300); Veja que neste caso, os valores dos campos NUMERO nas duas tabelas são iguais, estabelecendo a ligação entre os dois registros. Neste caso, estabelece-se que a conta especial de número 1 tem como limite o valor de R$ 300,00. É importante também ressaltar que as restrições sobre dados nulos e chaves34
  • 35. Programação IIIprimárias são verificadas na inserção de novos dados. Caso se tente burlar algumas destasregras, uma mensagem de erro é exibida, como no caso abaixo, onde tenta-se cadastraruma conta com número igual a de outra conta já cadastrada na base de dados. Figura 22 - Erro ao se tentar incluir um registro com uma chave primária já existente5.2 Visualizando dados das tabelas Até então, a certeza sobre a inserção dos dados nas tabelas só poderia ser verificadapelas respostas dos comandos INSERT realizados. Porém, uma maneira mais segura seriaverificar se os dados constam ou nas tabelas. Para isto, devemos utilizar o comando SELECT,cuja sintaxe simplificada é apresentada a seguir. SELECT { EXPRESSÃO | TABELA.CAMPO | * } [, ... ] FROM <<LISTA DE TABELAS> [WHERE <<EXPRESSÃO>>] [ORDER BY <<CAMPO>> [{ASC | DESC}] ] [GROUP BY <<EXPRESSÃO>> ] Esta é uma versão simplificada do comando SELECT. Existem outras cláusulas quenão serão apresentas aqui por questões de escopo da disciplina, e também porque ascláusulas aqui citadas serão suficientes para nossos exemplos. Na sua versão mais simples, é possível listar todos os registros e campos deuma determinada tabela. Por exemplo, caso você queira ver todos os registros da tabelaENDERECO, deve usar o comando a seguir: SELECT * FROM ENDERECO Este comando indica que queremos visualizar todos os campos de todos os registrosda tabela ENDERECO. Porém, é possível especificar que queremos ver apenas um conjuntodos campos, listando-os individualmente no comando SELECT, como exemplificado abaixo. SELECT RUA FROM ENDERECO 35
  • 36. Programação III Veja na Figura abaixo, o resultado da execução do comando SELECT no banco criado até então: Note que há outros registros. Estes registros foram inseridos propositadamente por meio de outros comandos INSERT. Note também que como havíamos dito, o campo ID_ ENDERECO tem valores numéricos que são atribuídos automaticamente para cada registro. Com isto, podemos utilizar o comando SELECT para visualizar qual o valor gerado para um registro de um endereço e depois utilizá-lo para inserir uma pessoa. Caso se queira refinar uma busca, é possível utilizar a cláusula WHERE. Esta cláusula define uma condição de busca que deve ser satisfeita por um registro para que ele seja retornado como resposta ao SELECT. Para definir esta condição, SQL utiliza operadores lógicos e relacionais já conhecidos das linguagens de programação. A tabela a seguir apresenta os operadores lógicos presentes em SQL. Tabela 2 – Operadores lógicos de SQL Operador Descrição “E” lógico, avalia duas condições e retorna verdadeiro apenas se ambas AND forem verdadeiras “OU” lógico, avalia duas condições e retorna verdadeiro se alguma das OR condições for verdadeira NOT Negacão lógica, retorna o valor contrário da expressão avaliada Em relação aos operadores relacionais, estes são usados para realizar comparações entre valores. A tabela abaixo apresenta os principais operadores relacionais presentes em SQL.36
  • 37. Programação III Tabela 3 – Operadores relacionais em SQL Operador Descrição < Menor > Maior <= Menor ou igual >= Maior ou igual = Igual != Diferente BETWEEN Utilizado para especificar um intervalo de valores Utilizado na comparação de um modelo e para especificar registros de um LIKE banco de dados.”Like” + extensão % vai significar buscar todos resultados com o mesmo início da extensão Para ilustrar sua utilização, vamos apresentar alguns exemplos. Para listar todas asruas de endereço localizados no bairro de Boa Viagem: Para listar todas as ruas que começam com a palavra ‘AVENIDA’: Para listar todas as ruas que começam com a palavra ‘AVENIDA’ e que o ID_ENDERECO estejam entre 1 e 3. 37
  • 38. Programação III A cláusula ORDER BY permite que os resultados apresentados sejam ordenados de acordo com seus valores. É possível definir tanto a ordenação crescente (que é o padrão), quanto decrescente de valores. Por exemplo, para listar os nomes de todas as ruas em ordem decrescente, utilizaríamos o seguinte comando SELECT RUA FROM ENDERECO ORDER BY RUA DESC Veja a execução do comando na figura abaixo Antes de valor sobre a última cláusula, a GROUP BY, é necessário dizer que SQL fornece também um conjunto de funções para agregação de valores. A cláusula GROUP utiliza estas funções para que os resultados de sua chamada sejam aplicadas em um conjunto de registros que são agrupados por um critério comum. A tabela a seguir apresenta as principais funções de agregação. Tabela 4 - Operadores escalares em SQL Função Descrição AVG Utilizada para calcular a média dos valores de um campo determinado COUNT Utilizada para devolver o número de registros da seleção SUM Utilizada para devolver a soma de todos os valores de um campo determinado MAX Utilizada para devolver o valor mais alto de um campo especificado MIN Utilizada para devolver o valor mais baixo de um campo especificado38
  • 39. Programação III Para exemplificar o uso das funções de agregação e da cláusula GROUP BY, tomecom exemplo a tabela CONTA, com os seguintes dados cadastrados. Imagine então que se queira saber qual é a média dos saldos entre todas as contascadastradas. Para isso, utiliza-se a função AVG, como apresentado a seguir. Caso se queira descobrir o maior e o menor saldo de uma conta, utiliza-se asfunções MAX e MIN, como ilustrado a seguir. A cláusula GROUP BY permite que as funções de agregação sejam agrupadas. Parailustrar, imagine a consulta onde se queira saber qual o menor e maior saldo das contas de 39
  • 40. Programação III cada correntista, dado que existem pessoas com mais de uma conta no banco. Para isto, utiliza-se a cláusula GROUP BY, como exemplificado a seguir. Note que nesta última consulta, utiliza-se um novo recurso. Cada campo utilizado na consulta pode ter um ‘apelido’. No caso, utiliza-se a palavras ‘AS’ como uma ligação entre o valor do campo e seu apelido. Este novo identificador é utilizado na resposta da consulta, como visto na Figura. Por fim, deixamos as consultas mais complexas. Imagine a situação onde você queira visualizar o nome de todos os correntistas que tenham contas especiais. Neste caso há um problema, pois a informação sobre o tipo da conta é armazenada na tabela CONTA, e o nome de cada correntista fica na tabela PESSOA. A princípio, teríamos que fazer duas consultas. Primeiro, descobrir quais são os cpfs das contas especiais na tabela CONTA, e depois utilizar estes valores para criar uma segunda consulta na tabela PESSOA. Porém, é possível fazer esta consulta com um único comando SQL, por meio da junção de tabelas. Veja que tanto a tabela CONTA, quanto a tabela PESSOA possuem um campo em comum: o CPF. Logo, este campo servirá de ligação entre as duas tabelas em uma consulta. A consulta que pretendemos é apresentada a seguir SELECT NOME FROM CONTA AS C, PESSOA AS P WHERE (TIPO = 1) AND (C.CPF = P.CPF) Nesta consulta, verifica-se que podem-se ser obtidos todos os campos das tabelas citadas na cláusula FROM, no caso, as tabelas CONTA e PESSOA. No caso, só estamos querendo retornar o nome. Este é um campo que só existe na tabela PESSOA, então o compilador SQL não vai se perder para obter esta informação. Caso houvessem dois campos com o mesmo nome em tabelas distintas, é necessário especificar qual campo de que tabela se deseja retorna. Para isto, deve-se utilizar o nome da tabela (ou seu apelido), seguido por um ponto “.” e o nome do campo. Note que da mesma forma que campos podem ser renomeados, tabelas também. Neste exemplo, CONTA passa ser referenciada por “C”, e PESSOA por “P”. Esta substituição é para diminuir o tamanho das cláusulas SQL. A junção das tabelas se dá na cláusula WHERE. Nela, além de se filtrar as contas pelo seu tipo, faz uma ligação entre as duas tabelas através dos números de CPF. A Figura a seguir apresenta a execução desta consulta no HyperSQL.40
  • 41. Programação III Outro exemplo de junção mais complexo seria: Qual o estado do endereçoresidencial do correntista cuja conta seja a de número 1? Neste caso, é necessário fazer a junção de 3 tabelas: CONTA, PESSOA e ENDERECO,pois o estado é parte da tabela ENDERECO, enquanto o número da conta está na tabelaCONTA. A única ligação entre as duas tabelas é a tabela PESSOA. A figura abaixo apresenta ocomando SELECT e sua execução no HyperSQL.5.3 Alterando dados em tabelas Uma vez que já existam dados, o comando UPDATE permite que os valores de umou vários campos de um ou mais registros sejam alterados. Sua sintaxe é descrita a seguir. UPDATE <<TABELA>> SET <<COLUNA1>> = <<VALOR1>>, <<COLUNA2>> = <<VALOR2>> [WHERE <<EXPRESSÃO>>] A idéia do comando UPDATE é especificar novos valores para campos que devemser alterados de acordo com uma condição de pesquisa. Por exemplo, imagine que se queiramodificar o nome do correntista ‘Fernando Trinta’ para ‘Fernando Antonio Mota Trinta’.Neste caso, utiliza-se o seguinte comando: UPDATE PESSOA SET NOME = ‘Fernando Antonio Mota Trinta’ WHERE CPF = ‘11111111111’ 41
  • 42. Programação III Note que neste caso, a condição indica que apenas o registro cujo CPF seja igual a ‘11111111111’ tenha o nome alterado para ‘’Fernando Antonio Mota Trinta’. De acordo com os dados cadastrados até então, só existe um registro que satisfaça esta condição, e este será o único registro alterado. Se não houvesse nenhum registro que satisfizesse a condição, nenhum registro seria alterado. É importante salientar que se nenhum condição de seleção for especificada na cláusula WHERE, a atualização se dá em todas os registros da tabela. Por exemplo, caso se queira aumentar o saldo de todas as contas em 50%. Neste caso, não há necessidade de se definir a cláusula WHERE, como ilustrado na figura abaixo. Duas observações importantes neste último exemplo. Primeiro, é possível utilizar expressões matemáticas para atualizações, assim como nos critérios de busca bem como nos resultados das consultas. Segundo, o resultado do comando UPDATE é o número de registros afetados por sua execução. No nosso exemplo, cinco linhas da tabela foram modificadas pelo comando UPDATE. 5.4 Removendo registros O último dos comandos DML é aquele que permite a exclusão de registros, o comando DELETE. A sintaxe simplificada do comando é apresentada a seguir DELETE FROM <<TABELA>> [ WHERE CONDIÇÃO ]42
  • 43. Programação III O comando DELETE remove todas os registros de uma determinada tabela queobedeçam ao critério de busca definido na cláusula WHERE. Se não for definido nenhumcritério, todas as linhas da tabela são removidas, o que indica que o comando deve serutilizado com cuidado. É importante também frisar que para que as linhas de uma coluna sejam removidas,as condições de integridade referencial entre os dados da tabela devem ser satisfeitos. Porexemplo, na tabela CONTAS, existem registros que são referenciados por outras tabelas,com as contas especiais ou poupanças. A tentativa de se remover um registro nestas condições ocasionará um erro, comoapresentado pela figura abaixo. Logo, para efetivamente se apagar um registro, deve-se seguir a ordem corretade remoção de dependência entre registros que estejam relacionados. No caso de nossoexemplo, primeiro deve-se apagar o registro na tabela CONTA_ESPECIAL, para entãoremover o registro na tabela CONTA, como apresentado a seguir. Note que os dois comandos (assim como mais de um comando) podem serdisparados na mesma janela. Estes são executados na ordem em que são digitados naferramenta. 43
  • 44. Programação III Exercícios 1. Utilizando o banco de dados HyperSQL, crie o seguinte esquema de tabelas para representar um banco de dados para uma discoteca de mídias (DVDs e CDs). Neste esquema, as chaves primárias são automáticas (tipo IDENTITY). 2. Utilizando comandos INSERT, cadastre os dados apresentados na figura 3. Utilizando o comando UPDATE, modifique o preço do DVD com nome “Berimbau Metalizado” para 39,90. 4. Utilizando o comando DELETE, tente remover o registro na tabela CANTOR que identifica a cantora “Ivete Sangalo”. Qual o resultado obtido? 5. Usando o comando SELECT, realize a seguintes consultas: 1) Quais são os nomes e o tempo das músicas cantadas por Michael Jackson? 2) Qual a soma total do tempo das músicas do DVD “berimbau metalizado”? 3) Quem são os cantores que não tem mídias cadastradas na base? 4) Qual o CD mais caro e o mais barato da base? 5) Qual a média de preço de CDs? 6) Qual a música mais longa de Ivete Sangalo?44
  • 45. Programação III Vamos Revisar? Resumo A linguagem SQL é o padrão para manipulação de bases de dados. Conhecê-la éimprescindível para que se possa realizar ações nos SGBDs atuais. Este capítulo apresentoude forma resumida, alguns dos principais comandos da linguagem. No próximo capítulo,veremos como podemos utilizar a linguagem SQL dentro de classes de sistemas escritos emJava. 45
  • 46. Programação III Capítulo 3 O que vamos estudar neste capítulo? Neste capítulo, vamos estudar o seguinte tema: » A especificação Java Database Connectivity. Metas Após o estudo deste capítulo, esperamos que você consiga: » Entender as principais classes e interfaces da API JDBC; » Criar programas que permitam interagir com um banco de dados.46
  • 47. Programação IIICapítulo 3 – A especificação JDBC Vamos conversar sobre o assunto? Caro cursista, Nos capítulos anteriores deste volume vimos os conceitos básicossobre bancos de dados e a sintaxe básica da linguagem SQL, padrão para manipulação debancos de dados relacionais. Este capítulo utiliza estas informações para apresentar comoaplicações escritas em uma linguagem de programação, no caso Java, possa interagir comum SBGD, de modo a persistir suas informações.1. Introdução Por tudo que já foi visto neste volume, é fácil perceber a importância que os bancosde dados tem para os sistemas e aplicações modernas. Como meio padrão para guardaras muitas informações geradas pelos sistemas de informação, estas aplicações se tornaramimprescindíveis para praticamente qualquer tipo de sistema atualmente. SQL é a linguagem padrão para acesso a banco de dados e se estabeleceu comotal no mercado. No entanto, ela não é adequada para o desenvolvimento de aplicações ena prática é dependente de SGDB e de plataforma. O que viu-se então foi a necessidade depermitir que aplicações escritas em linguagens de programação convencionais pudesseminteragir com os SBGDs. O que aconteceu foi que cada SBGD apresentava sua forma depermitir tal acesso. Em geral, as abordagens permitiam que comandos SQL pudessem serexecutados a partir de programas externos. Apesar desta similaridade, cada SGBD possui arquitetura interna e detalhes deimplementação que lhes são particulares. Neste contexto, cada um destes SGBDs possuiuma forma específica de permitir a comunicação de programas externos com suas bases dedados, como ilustrado na figura abaixo. É fácil perceber que este cenário traz uma série de problemas em relação àportabilidade das aplicações. Se por um acaso uma aplicação precisasse mudar o SGBD,seriam necessárias mudanças no código de suas aplicações, gerando um série problema demanutenção e flexibilidade para as empresas. Os desenvolvedores também sofriam por terque aprender diferentes formas e APIs para conexão com cada SGBD diferente, criando umpesadelo para os programadores. Estava claro que este era um cenário que não poderia continuar a existir. No casoda linguagem, a solução está na adição de uma camada adicional que procura abstrair e 47
  • 48. Programação III padronizar o acesso a qualquer SGBD. Esta camada, proposta pela Sun Microsystems, é chamada de Java Database Conectivity (JDBC), e tem como proposito básico, uniformizar o acesso a banco de dados relacionais, de modo a aumentar a flexibilidade de sistemas desenvolvidos em Java. Com o uso de JDBC, o acesso ao SGBD é padronizado por meio de chamadas SQL. Este capítulo vai apresentar JDBC, suas principais classes e interfaces. Através dos exemplos, você vai aprender como criar programas em Java que disparem consultas em bancos de dados relacionais. 2. JDBC Na prática, JDBC é uma API de baixo nível, formada por um conjunto de classes e interfaces escritas em Java que faz o envio de instruções SQL para qualquer banco de dados relacional. Na realidade, JDBC é uma especificação, o que indica que os fornecedores de SGBDs podem seguir as regras desta especificação para implementar o acesso aos seus produtos para desenvolvedores em Java. O segredo para o correto funcionamento de SGBD é sua arquitetura em camadas, como ilustrado em sua arquitetura na figura abaixo. Figura 23 - Visão de múltiplas camadas de JDBC Nesta figura, no nível mais baixo, ressalta-se que cada banco de dados possui um elemento chamado Driver, um componente de software que fornece a conexão ao banco de dados e implementa o protocolo para transferir a consulta e o resultado entre cliente e banco de dados. O Driver JDBC é quem realmente estabelece e gerencia conexões com o banco de dados. Este Driver mascara todo detalhe que é específico de um banco de dados particular. Cada fornecedor implementa e distribui este driver para que os programadores Java possam integrar seus programas com um SGBD em particular. Na realidade, JDBC permite que seus drivers sejam implementados de 4 formas distintas, como apresentado a seguir.48
  • 49. Programação III Figura 24 - Modos de funcionamento para JDBC A primeira forma é utilizando uma ponte JDBC-ODBC. ODBC (acrônimo de OpenData Base Connectivity) é uma outra abordagem para acesso a bases de dados. Neste tipode abordagem, é necessário configurar a máquina cliente para estabelecer a conexão como banco, como no caso dos sistemas operacionais da família Windows. A segunda opçãoé aquela em que as chamadas JDBC são convertidas em chamadas nativas do Banco, oque garante ganhos de desempenho, porém menor portabilidade. A terceira abordagemé a utilização de um middleware, que converte chamadas JDBC em um protocolo de redeindependente do SGBD e comunicam-se com um intermediário (gateway) que traduz estasrequisições para o protocolo específico do SGBD. Esta abordagem possibilitam o uso dediferentes SGBDs, sendo a mais flexível alternativa dentre as alternativas apresentadas.Sua utilização também permite que os bancos sejam acessados pela Internet, porém comcuidados adicionais com a segurança. Por fim, a quarta alternativa é aquela em que aschamadas JDBC são convertidas em um protocolo de rede usado diretamente pelo SGBD.Esta é uma solução puramente escrita em Java e que não requer nenhum código adicionalno cliente. Independente de qual seja a estratégia utilizando, acima do driver há umcomponente chamado DriverManager, que gerencia os drivers disponíveis para as aplicaçõese que serve de ponte para que a API JDBC possa disparar comandos SQL nos programasescritos em Java. O ponto de contato do programador Java e JDBC é através da API JDBC, que defineum conjunto de classes da linguagem Java que representam conexões à bancos de dados,consultas SQL, resultados de consultas, informações sobre bancos de dados, etc., ouseja, permite ao programador Java consultar bancos de dados e manipular os resultadosdas consultas. As interfaces classes de JDBC são agrupadas no pacote java.sql e sãorepresentadas na figura abaixo. 49
  • 50. Programação III Figura 25 - API JDBC Neste capítulo veremos como usar as principais classes desta API, que são elas: » DriverManager - gerencia o driver e cria uma conexão com o banco; » Connection - é a classe que representa a conexão com o banco de dados. » Statement - controla e executa uma instrução SQL ; » PreparedStatement - controla e executa uma instrução SQL, por meio de parâmetros. Em geral, seu uso é mais indicado que do Statement; » ResultSet - contém o conjunto de dados retornado por uma consulta SQL. Antes disso, vamos preparar o nosso ambiente de desenvolvimento para trabalhar com JDBC. 3. Configurando eclipse para usar JDBC Antes de começarmos a ver como se utiliza na prática a API JDBC, é preciso configurar o ambiente para tal utilização. Como visto na seção anterior, para acessar um SGBD, é necessário possuir um driver de acesso para tal banco. Estes drivers são disponibilizados nos sites das empresas e fornecedores dos SGBDs como um arquivo JAR. Em nossos exemplos, o banco utilizado será o HyperSQL, cujo driver JDBC é o próprio arquivo hsqldb.jar, que também representa o próprio banco. Para que o driver seja utilizado pela aplicação, é necessário adicionar o arquivo JAR no classpath da aplicação ou no momento da chamada do interpretador Java. Quando se utiliza ambientes integrados de desenvolvimento, como Eclipse ou Netbeans, é necessário incluir este arquivo nas configurações dos projetos. Nesta disciplina, para manter a compatibilidade com os capítulos anteriores, será utilizado o Eclipse, e os próximos parágrafos apresentam os passos necessários para a configuração de um projeto que utilize JDBC para acessar o HyperSQL. Primeiramente é necessário ter um projeto Java criado. Neste projeto é interessante criar uma pasta para guardar o arquivo do driver que será utilizado. Esta abordagem permite que quando se queira copiar ou mudar o projeto de localização, os arquivos do driver sejam levados também, evitando a quebra de dependência da aplicação. Para criar uma pasta, basta clicar com o botão direito sobre o projeto, seguido pela opção New. Esta opção abrirá um outro sub-menu. Neste sub-menu, deve-se escolher a opção Folder, como ilustrado na50
  • 51. Programação IIIFigura abaixo. Figura 26 - Configurando o eclipse para usar JDBC (Passo 1) Ao selecionar esta opção, uma janela será apresentada para que a nova pasta sejacriada. Deve ser selecionado o nome do projeto para que a nova pasta seja criada na raizdo próprio projeto. Por padrão, o nome desta pasta é definido como lib (do inglês, libraries).Esta pasta representa todas as bibliotecas necessárias para correta execução dos programasdo projeto. O driver JDBC pode ser também visto como uma destas bibliotecas. Digitado onome, pode-se clicar sobre o botão finish. Figura 27 - Configurando o eclipse para usar JDBC (Passo 2) 51
  • 52. Programação III A pasta pode ser visualizada no projeto. Porém ainda falta copiar o driver para dentro deste diretório. Figura 28 - Configurando o eclipse para usar JDBC (Passo 3) A cópia do arquivo pode ser feita tanto diretamente pelo sistema operacional, quanto pelo Eclipse. Para isto, deve-se utilizar o gerenciador de arquivos do sistema (no windows é o Explorer), selecionar o arquivo hsqldb.jar no diretório onde o mesmo esteja armazenado e com o botão direito, utilizar a opção “copiar”. O mesmo procedimento pode ser feito com as conhecidas teclas de atalho <control> + <C>. Com o arquivo copiado, deve- se selecionar a pasta lib no eclipse, e com o botão direito, escolher a opção “Paste” (Colar, em inglês). Figura 29 - Configurando o eclipse para usar JDBC (Passo 4)52
  • 53. Programação III Este procedimento copiará o arquivo para dentro do projeto do Eclipse, com podeser observado na figura abaixo. Figura 30 - Configurando o eclipse para usar JDBC (Passo 5) Para finalizar o processo de configuração é necessário fazer com que o projetoJava entenda que o arquivo hsqldb.jar é um arquivo que deve ser considerado quando dacompilação das classes codificadas no projeto. Para fazer isto, deve modificar as propriedadesdo projeto, clicando com o botão direito sobre o nome do projeto, e escolhendo a últimaopção do menu, com apresentado na figura abaixo. Figura 31 - Configurando o eclipse para usar JDBC (Passo 6) Ao fazer esta operação é apresentada uma janela com várias opções em relação ao 53
  • 54. Programação III projeto. A opção que procuramos é Java Build Path, localizada à esquerda da Janela, e que permite incluir novos arquivos no classpath do projeto. Para isto, deve-se selecionar a aba libraries na parte superior da janela. Selecionada esta aba, clique sobre o botão add jars. Figura 32 - Configurando o eclipse para usar JDBC (Passo 7) Depois de clicar sobre o botão, deve ser apresentada uma janela com os arquivos que fazem parte do projeto e que podem ser incluídos como bibliotecas. Selecione o arquivo hslqbd.jar e pressione o botão OK. Figura 33 - Configurando o eclipse para usar JDBC (Passo 8)54
  • 55. Programação III Feito isso, o projeto estará configurado para criar classes que utilizem a API JDBCpara acessar o banco HyperSQL. Caso seja necessário acessar um outro banco qualquer, adiferença será o arquivo a ser utilizado, porém os passos necessários para configuração doeclipse serão basicamente os mesmos.4. Utilizando a API JDBC Configurado o projeto, podemos agora utilizar a API JDBC para executar operaçõessobre o banco. Nos exemplos deste capítulo, utilizaremos a base de dados do sistema decontrole bancário, criada no HyperSQL. Portanto, além dos passos de configuração realizadosna seção anterior, é também requisito que a base de dados com as tabelas CONTA, PESSOA,ENDERECO, CONTA_ESPECIAL e POUPANCA tenham sido criadas seguindo os passos docapítulo anterior, bem como que o banco ativo durante a execução dos programas destecapítulo4.1 Estabelecendo uma conexão com o banco Para a aplicação Java se comunicar com um banco de dados, uma conexão como banco deve ser estabelecida. Esta conexão é estabelecida de seguinte forma. Primeiro,o driver JDBC do banco em questão deve ser carregado. Em seguida, deve ser criada umaconexão com o banco para realização de consultas e atualizações. Para se carregar um driver utiliza-se a construção Class.forName(“Nome doDriver”). Cada forneceder possui uma classe específica que implementa o driver JDBC deacesso ao seu banco de dados. Esta classe deve estar contida dentro do arquivo JAR incluídono classpath da aplicação. É necessário ter acesso a documentação do driver JDBC parasaber qual o nome completo desta classe. No caso do HyperSQL, a classe que implementado driver é a org.hsqldb.jdbc.JDBCDriver. Sendo assim, para carregar o driver do HyperSQL,basta utilizar o trecho de código descrito abaixo. try { Class.forName(“org.hsqldb.jdbc.JDBCDriver”); } catch (ClassNotFoundException e) { e.printStackTrace(); } Note que a chamada ao método Class.forName precisa tratar a exceção deClassNotFoundException, pois pode acontecer se tentar carregar um driver não existente. Com o driver existente e disponível, deve-se então utilizar o Driver Manager paramanipulá-lo. A classe DriverManager implementa esta gerencia dos drivers disponíveis.Porém, é necessário identificar cada banco individualmente. Para isto, utiliza-se uma URL,cujo formato é descrito abaixo: Cada aplicação utiliza o subprotocolo para identificar e selecionar o driver aser instanciado, enquanto o dsn é o nome que o subprotocolo utilizará para localizar um 55
  • 56. Programação III determinado servidor ou base de dados. Desta forma é possível utiliza dois esquemas distintos em uma mesma base de dados. Esta sintaxe é dependente de cada fabricante. Por exemplo, o Oracle utiliza a seguinte sintaxe: jdbc:oracle:thin:@200.206.192.216:1521:exemplo No caso do HyperSQL, a URL de acesso é dada de acordo com o modo de uso do banco. No modo que está sendo usado nos exemplos deste livro, a URL de acesso é dada por: jdbc:hsqldb:hsql://localhost/ A classe DriverManager é uma classe estática, que possui métodos para registrar, remover e listar drivers JDBC. É através do DriverManager que se consegue estabelecer uma conexão válida com o banco. Para isto, utiliza-se o método getConnectio, que possui várias versões sobrecarregadas. A mais comum delas, é que recebe a URL de acesso ao banco, o nome do usuário do banco e sua senha. No caso do HyperSQL, para se acessar o banco criado deve-se utilizar então a chamada: Connection con = DriverManager.getConnection( “jdbc:hsqldb:hsql://localhost/”, “SA”, “”); O retorno desta chamada é um objeto do tipo Connection, que representa uma conexão com o banco de dados, e que permite que as operações realizadas por outras classes da API sejam repassadas ao SGBD. Sendo assim, o trecho de código padrão para abertura de conexão com um banco é descrito abaixo. try { Class.forName(“org.hsqldb.jdbc.JDBCDriver”); Connection con = DriverManager.getConnection(“jdbc:hsqldb:hsql://localhost/”, “SA”, “”); } catch (ClassNotFoundException e) { e.printStackTrace(); } catch (SQLException e) { e.printStackTrace(); } Note que agora, uma nova exceção precisa ser tratada, a SQLException. Esta exceção está presente em praticamente toda operação de manipulação com o banco, pois estas ações estão sujeitas a problemas. Por exemplo, o banco não estar em execução ou indisponível. Erros também podem acontecer em operações de bancos válidos, como ao tentar acessar uma tabela que não exista. Portanto, praticamente toda operação de manipulação com o banco, como a abertura de uma conexão, deve tratar a exceção SQLException. 4.2 Acessando o banco de dados Com a conexão estabelecida, é possível interagir com o banco de várias formas, como: » Criar tabelas e outros elementos; » Adicionar, alterar e remover registros de tabelas existentes; » Buscar registros. Para realizar estas operações, utilizaremos as interfaces Statement,56
  • 57. Programação IIIPreparedStatement e ResultSet. As duas primeiras são utilizadas para realizar as operaçõesno banco, enquanto a última serve para obter o resultado de uma consulta sobre umatabela. Vamos primeiro utilizar a interface Statement. Um objeto Statement é obtido apartir de um objeto Connection válido que representa uma declaração SQL que deve serexecutada no SGBD por meio do método createStatement(). As ações possíveis para oStatement são executadas por métodos específicos para consultas, atualizações. Dentre osprincipais métodos estão: » executeUpdate(): usado para operações que causam alteração na base de dados (create, insert , update, etc); » executeQuery(): usado em operações de consulta à base de dados. Ambos recebem como parâmetro uma string com o comando SQL a ser executadona base. A classe a seguir ilustra como exemplo um programa para inserir um novo endereçona tabela ENDERECO criada no capítulo passado. import java.sql.Connection; import java.sql.DriverManager; import java.sql.SQLException; import java.sql.Statement; public class ExemploJDBC { public static void main(String[] args) { try { Class.forName(“org.hsqldb.jdbc.JDBCDriver”); Connection con = DriverManager.getConnection( “jdbc:hsqldb:hsql://localhost/”, “SA”, “”); Statement stmt = con.createStatement(); String sql = “INSERT INTO ENDERECO(RUA, NUMERO, “ + “BAIRRO, CIDADE, ESTADO, CEP) “ + “VALUES(‘Avenida Washington Soars’,’1233’,’Edson Queiroz’, “ + “’Fortaleza’,’Ceará’, ‘60800876’)”; stmt.executeUpdate(sql); stmt.close(); con.close(); } catch (ClassNotFoundException e) { e.printStackTrace(); } catch (SQLException e) { e.printStackTrace(); } } } Ao final da execução e uso dos objetos Statement e Connection, o método close()deve ser invocado. Da mesma forma como os streams, manter conexões com o banco dedados requer que recursos do sistema sejam alocados. O método close() faz com que estesrecursos sejam liberados para o sistema e possam ser utilizados para outros fins. É muitoimportante fazer esta reposição dos recursos para que o programa não cause problemas dedesempenho, ou mesmo com falta de memória para. 57
  • 58. Programação III Para verificar se o programa funcionou corretamente, você pode acessar o banco pela aplicação DatabaseManagerSwing, utilizada no capítulo passado e realizar uma consulta, como ilustrado a seguir. Este mesmo princípio pode ser utilizado para realizar comandos outros comandos DML como UPDATE, DELETE, SELECT, bem como comandos DDL, como CREATE TABLE, ALTER TABLE e DROP TABLE. O programa a seguir mostra uma atualização sobre a tabela CONTA, utilizando o comando UPDATE para aumentar em 50% o valor do saldo de cada conta. import java.sql.Connection; import java.sql.DriverManager; import java.sql.SQLException; import java.sql.Statement; public class ExemploJDBC { public static void main(String[] args) { try { Class.forName(“org.hsqldb.jdbc.JDBCDriver”); Connection con = DriverManager.getConnection( “jdbc:hsqldb:hsql://localhost/”, “SA”, “”); Statement stmt = con.createStatement(); String sql = “UPDATE CONTA SET SALDO = SALDO * 1.5”; int registros = stmt.executeUpdate(sql); System.out.println(“Registros afetados: “+registros); stmt.close(); con.close(); } catch (ClassNotFoundException e) { e.printStackTrace();58
  • 59. Programação III } catch (SQLException e) { e.printStackTrace(); } } } Note que a execução do método executeUpdate retorna o número de linhasafetadas pelo comando SQL, e que este valor pode ser utilizado no programa Java. No caso de consultas, a recuperação de dados do BD é trivial e é feita através daexecução de uma consulta SQL utilizando o método executeQuery, onde os dados sãoencapsulados em um objeto do tipo ResultSet, retornada na execução da consulta. Este objeto é uma estrutura que mantem os dados resultantes de um consulta àbase de dados, representando um cursor para os registros retornadas na consulta, ondepode-se navegar pelos resultados e recuperar as informações armazenadas nas colunas.Quando esta estrutura é retornada, o cursor de navegação é posicionado antes do primeiroregistro retornado. A partir daí, pode-se utilizar os seguintes métodos para navegação: Tabela 5 - Métodos da interface ResultSet Posiciona o ResultSet um registro a frente. Caso esteja além da última next() linha retornará false. Posiciona o ResultSet um registro atrás. previous() Caso esteja além da primeira linha retornará false. first() Posiciona o ResultSet no primeiro registro. last() Posiciona o ResultSet no último registro. Os métodos descritos acima navegam sobre os registros. Para acessar as colunasde cada registro por meio de métodos getInt(), getString, getFloat e outros métodos quemapeiam os tipos dos campos em tipos da linguagem Java. Cada um destes métodos recebecomo parâmetro o nome da coluna do banco. A tabela abaixo apresenta alguns métodosutilizados para recuperação de informações com o ResultSet. Figura 34 - Métodos getXXX da interface ResultSet 59
  • 60. Programação III Para melhor exemplificar o uso de consultas, a listagem abaixo apresenta uma classe que lista todos os registros da tabela CONTA. import java.sql.Connection; import java.sql.DriverManager; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; public class ExemploJDBC { public static void main(String[] args) { try { Class.forName(“org.hsqldb.jdbc.JDBCDriver”); Connection con = DriverManager.getConnection( “jdbc:hsqldb:hsql://localhost/”, “SA”, “”); Statement stmt = con.createStatement(); String sql = “SELECT * FROM CONTA”; ResultSet rs = stmt.executeQuery(sql); while(rs.next()){ String cpf = rs.getString(“CPF”); int num = rs.getInt(“NUMERO”); double saldo = rs.getDouble(“SALDO”); System.out.println(“Conta: “+num); System.out.println(“Saldo: “+saldo); System.out.println(“CPF correntista: “+ cpf); System.out.println(“----------------------------”); } rs.close(); stmt.close(); con.close(); } catch (ClassNotFoundException e) { e.printStackTrace(); } catch (SQLException e) { e.printStackTrace(); } } } A Figura a seguir apresenta a execução da classe.60
  • 61. Programação III Figura 35 – Execução do programa de listagem de contas4.3 Parametrizando consultas Os exemplos descritos até agora neste capítulo tem utilizado consultas SQL prontas,que são passadas para o objeto Statement e, posteriormente executadas. Porém, em seuuso prático, a integração entre programas e JDBC indica que as consultas receberão valoresdo programa para construir dinamicamente as consultas que deverão ser executadas noSGBD. Com o uso de Statement, isso é feito simplesmente concatenando o valor aocomando SQL a ser executado, como exemplificado no código abaixo. Neste exemplo, ousuário fornece o número da conta da qual deseja as informações. import java.sql.Connection; import java.sql.DriverManager; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; import java.util.Scanner; public class ExemploJDBC { public static void main(String[] args) { try { Class.forName(“org.hsqldb.jdbc.JDBCDriver”); Connection con = DriverManager.getConnection( “jdbc:hsqldb:hsql://localhost/”, “SA”, “”); Statement stmt = con.createStatement(); Scanner sc = new Scanner(System.in); System.out.println(“Digite o número da conta:”); 61
  • 62. Programação III int numero = sc.nextInt(); String sql = “SELECT * FROM CONTA WHERE NUMERO = “ + numero; ResultSet rs = stmt.executeQuery(sql); while(rs.next()){ String cpf = rs.getString(“CPF”); int num = rs.getInt(“NUMERO”); double saldo = rs.getDouble(“SALDO”); System.out.println(“Conta: “+num); System.out.println(“Saldo: “+saldo); System.out.println(“CPF correntista: “+ cpf); System.out.println(“----------------------------”); } rs.close(); stmt.close(); con.close(); } catch (ClassNotFoundException e) { e.printStackTrace(); } catch (SQLException e) { e.printStackTrace(); } } } Apesar de correta, esta forma não é a melhor e nem a mais indicada, pois acarreta em um trabalho de concatenação extremamente entediante e tendencioso a erros, principalmente na construção de SQLs maiores. Além disso, SQLs maliciosos podem ser embutidos e gerar problemas de segurança. Por tais questões, uma alternativa é o uso da interface PreparedStatement. Um PreparedStatement representa um comando SQL pré-compilado, o que também representa uma otimização de recursos, principalmente quando se tem várias consultas similares com parâmetros distintos. Em um PreparedStatement, as cláusulas SQL são criadas com pontos de interrogação (?) no lugar dos parâmetros da consulta. Para criar um PreparedStatement, a consulta parametrizada deve ser passada ao método prepareStatement. Com o objeto PreparedStatement, cada parâmetro é inserido com métodos do tipo set<<Tipo>>, onde os tipos são semelhantes àqueles definidos no ResultSet. Cada método set<<Tipo>> recebe dois parâmetros: o número do parâmetro a ser substituído de acordo com a ordem da consulta e o valor a ser substituído na consulta. O trecho de código abaixo representa como seria uma versão do programa anterior utilizando PreparedStatement. Scanner sc = new Scanner(System.in); System.out.println(“Digite o número da conta:”); int numero = sc.nextInt(); String sql = “SELECT * FROM CONTA WHERE NUMERO = ?”; PreparedStatement pstmt = con.prepareStatement(sql); pstmt.setInt(1, numero); ResultSet rs = pstmt.executeQuery(); while(rs.next()){ String cpf = rs.getString(“CPF”);62
  • 63. Programação III int num = rs.getInt(“NUMERO”); double saldo = rs.getDouble(“SALDO”); System.out.println(“Conta: “+num); System.out.println(“Saldo: “+saldo); System.out.println(“CPF correntista: “+ cpf); System.out.println(“----------------------------”); } Os parâmetros, com PreparedStatement, podem ser passados directamentecom o próprio tipo que o dado foi definido, evitando assim ter que ficar formatando ouconvertendo campos de data e decimais, além de poder passar inclusive valores nulos.5. Transações com JDBC Os comandos SQL executados em um banco de dados realizam ações individuaissobre as tabelas. Dependendo do tipo de processamento, uma determinada funcionalidadede um sistema precisa realizar mais de uma ação em várias tabelas do banco de dados.Se estas ações modificarem o conteúdo das tabelas, apenas a correta execução de todosos comandos garantirá a consistência da base de dados. Porém, em algum momento notempo, todo sistema computacional apresenta uma falha. Se esta falha ocorrer no meio darealização de um conjunto de comandos SQLs relacionados a uma única funcionalidade, eapenas alguns dos comandos forem executados, um problema está criado. Para exemplificar, um clássico exemplo é a realização de uma transferência entreduas contas. A transferência implica que um determinado valor precisa ser debitado deuma conta e creditado em outra conta. Falando em termos de SQL, dois comandos UPDATEprecisam ser realizados em dois registros distintos. Se por um azar qualquer, uma falhaocorrer depois que o UPDATE de débito tiver sido realizado, mas antes que o UPDATE decrédito seja efetivado, a operação de transferência irá gerar uma inconsistência na base. A solução para questões semelhantes está no conceito de transações. Umatransação equivale a agrupar um conjunto de operações e tratá-las com uma só, de talforma que se a transação for executada, haja garantia que todos sejam executados. Emcontrapartida, se a transação apresentar falha, nenhuma de suas ações deve ser realizada.Resumidamente, é o princípio do “tudo ou nada”, ou seja, ou se executa todas as operaçõesde uma transação ou o efeito é o mesmo que nenhuma tenha sido executada. O controle transacional é feito por meio da interface Connection. Toda conexãoaberta com o banco possui um modo de operação para transações ou modo de autocommit. Commit é um termo muito utilizado na área de banco de dados para se ilustrarque uma operação deve ser efetivada realmente no SGBD. O padrão de operação domodo auto commit de uma conexão é aquele em que toda operação de atualização sãoprocessadas imediatamente após serem recebidas. Porém, é possível modificar este modode operação. Por meio do método setAutoCommit(false), o desenvolvedor pode fazer comque a efetivação de um conjunto de operações seja acumlado, deixando que este momentoseja definido explicitamente pelo desenvolvedor. Para isto, dois métodos adicionais da interface Connection devem ser utilizados: ocommit e o rollback. O primeiro serve para efetivar o conjunto de instruções acumulados emum conexão até um dado instante, enquanto a segunda é utilizada para desfazer o processo,caso algum erro seja detectado no meio de uma transação. A listagem abaixo exemplifica o tratamento de uma transação para se fazer uma 63
  • 64. Programação III transferência entre duas contas do banco. Note que só ao final da realização de todas os statements, os comandos são realmente efetivados no banco por meio da chamada ao método con.commit. Caso aconteça alguma erro e a exceção SQLException seja levantada, os comandos até então realizados são desfeitos através do método con.rollback. import java.sql.Connection; import java.sql.DriverManager; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; import java.util.Scanner; public class ExemploTransação { public static void main(String[] args) { Connection con = null; try { Class.forName(“org.hsqldb.jdbc.JDBCDriver”); con = DriverManager.getConnection(“jdbc:hsqldb:hsql://localhost/”, “SA”, “”); con.setAutoCommit(false); String sql1 = “UPDATE CONTA SET SALDO = SALDO - 30 WHERE NUMERO = 2”; String sql2 = “UPDATE CONTA SET SALDO = SALDO + 30 WHERE NUMERO = 11”; Statement stmt1 = con.createStatement(); Statement stmt2 = con.createStatement(); stmt1.executeUpdate(sql1); stmt2.executeUpdate(sql2); con.commit(); stmt1.close(); stmt2.close(); con.close(); } catch (ClassNotFoundException e) { e.printStackTrace(); } catch (SQLException e) { e.printStackTrace(); if (con != null) try { con.rollback(); } catch (SQLException e1) { e1.printStackTrace(); } } } } 6. Integrando o Banco com o Sistema de Contas Com o conhecimento da API, a integração do sistema bancário com o HyperSQL tende a ser tranquila. Lembrando nossa aplicação, o banco manipular um conjunto de contas que pode ser armazenado em diferentes estruturas de dados. Estas estruturas devem seguir64
  • 65. Programação IIIo contrato definido pela interface ConjuntoContas, listada a seguir. package ufrpe.contas; public interface ConjuntoContas { public void inserir(Conta conta) throws RepositorioException, ContaJaCadastradaException; public void atualizar(Conta conta) throws RepositorioException, ContaInexistenteException; public void remover(int numero) throws RepositorioException, ContaInexistenteException; public Conta procurar(int numero) throws RepositorioException, ContaInexistenteException; public void transferir(int contaOrigem, int contaDestino, float valor) throws RepositorioException, ContaInexistenteException, SaldoInsuficienteException; public Conta[] getContas() throws RepositorioException; } É importante notar que o primeiro passo é a interface está modificada em relaçãoàs versões anteriores apresentadas em outros capítulos de nossa disciplina. Agora, todosos métodos além de levantarem exceções específicas como ContaInexistenteExceptionou ContaJaCadastradaException, levantam também a exceção RepositorioException. Estaexceção representa todo e qualquer problema que possa acontecer com o armazenamentodas informações no meio de persistência encontrado. No caso do SGBD, tais problemaspodem ocorrer pelo fato do banco não estar ativo, as tabelas não estarem criadas,dentre outros fatores. Logo, todo vez que este tipo de problema acontecer, a exceçãoRepositorioException precisará ser levantada. A criação desta exceção visa abstrair tambémo meio de armazenamento utilizado. Por exemplo, caso se opte por usar arquivos, o erro degravação ou outro motivo qualquer também devem levantar RepositorioException. A classeRepositorioException é uma classe de exceção convencional, como listado a seguir. package ufrpe.contas; public class RepositorioException extends Exception { public RepositorioException(String message) { super(message); } } A etapa mais trabalhosa é a criação de um conjunto de contas que utilize o SBGDpara armazenar os dados da aplicação. Para isto, deve-se então definir uma classe queimplemente os métodos da interface ConjuntoContas, como a classe ConjuntoContasBD,listada a seguir. Esta é uma classe razoavelmente extensa, em que explicaremos seusprincipais métodos. 65
  • 66. Programação III package ufrpe.contas; import java.sql.Connection; import java.sql.DriverManager; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; import java.util.ArrayList; import java.util.List; import ufrpe.pessoas.Endereco; import ufrpe.pessoas.Pessoa; public class ConjuntoContasBD implements ConjuntoContas { private Connection con = null; public ConjuntoContasBD() { try { con = criaConexao(); } catch (SQLException e) { System.out.println(“Problemas ao conectar com SGBD...”); System.out.println(“Encerrando aplicação...”); System.exit(0); } } private Connection criaConexao() throws SQLException { try { Class.forName(“org.hsqldb.jdbc.JDBCDriver”); } catch (ClassNotFoundException e) { System.out.println(“Problemas ao carregar Driver JDBC...”); System.out.println(“Encerrando aplicação...”); System.exit(0); } return DriverManager.getConnection(“jdbc:hsqldb:hsql://localhost/”, “SA”, “”); } public Conta procurar(int numero) throws ContaInexistenteException, RepositorioException { Conta c = null; try { String sql = “SELECT * FROM CONTA, PESSOA WHERE (NUMERO = ?) AND (CONTA.CPF = PESSOA.CPF)”; PreparedStatement pstmt = con.prepareStatement(sql); pstmt.setInt(1, numero); ResultSet rs = pstmt.executeQuery();66
  • 67. Programação IIIif (rs.next()) { float saldo = (float) rs.getDouble(“SALDO”); int tipo = rs.getInt(“TIPO”); String cpf = rs.getString(“CPF”); String nome = rs.getString(“NOME”); char sexo = rs.getString(“SEXO”).charAt(0); int idEndCom = rs.getInt(“END_COMERCIAL”); int idEndRes = rs.getInt(“END_RESIDENCIAL”); rs.close(); pstmt.close(); String sql2 = null; PreparedStatement pstmt2 = null; ResultSet rs2 = null; double limite = 0; int diaAniv = 0; switch (tipo) { case 1: sql2 = “SELECT * FROM CONTA_ESPECIAL WHERE NUMERO = ?”; pstmt2 = con.prepareStatement(sql2); pstmt2.setInt(1, numero);/ rs2 = pstmt2.executeQuery(); if (rs2.next()) { limite = rs2.getDouble(“LIMITE”); } rs2.close(); pstmt2.close(); break; case 2: sql2 = “SELECT * FROM POUPANCA WHERE NUMERO = ?”; pstmt2 = con.prepareStatement(sql2); pstmt2.setInt(1, numero); rs2 = pstmt2.executeQuery(); if (rs2.next()) { diaAniv = rs2.getInt(“DIA_ANIVERSARIO”); } rs2.close(); pstmt2.close(); break; } String sqlEnd = “SELECT * FROM ENDERECO WHERE ID_ENDERECO = ?”; pstmt2 = con.prepareStatement(sqlEnd); pstmt2.setInt(1, idEndRes); rs2 = pstmt2.executeQuery(); String ruaRes = null, numRes = null, bairroRes = null, cidadeRes = null, estadoRes = null, cepRes = null; if (rs2.next()) { ruaRes = rs2.getString(“RUA”); numRes = rs2.getString(“NUMERO”); bairroRes = rs2.getString(“BAIRRO”); 67
  • 68. Programação III cidadeRes = rs2.getString(“CIDADE”); estadoRes = rs2.getString(“ESTADO”); cepRes = rs2.getString(“CEP”); } pstmt2 = con.prepareStatement(sqlEnd); pstmt2.setInt(1, idEndCom); rs2 = pstmt2.executeQuery(); String ruaCom = null, numCom = null, bairroCom = null, cidadeCom = null, estadoCom = null, cepCom = null; if (rs2.next()) { ruaCom = rs2.getString(“RUA”); numCom = rs2.getString(“NUMERO”); bairroCom = rs2.getString(“BAIRRO”); cidadeCom = rs2.getString(“CIDADE”); estadoCom = rs2.getString(“ESTADO”); cepCom = rs2.getString(“CEP”); } rs2.close(); pstmt2.close(); Endereco endRes = new Endereco(ruaRes, numRes, bairroRes, cidadeRes, estadoRes, cepRes); Endereco endCom = new Endereco(ruaCom, numCom, bairroCom, cidadeCom, estadoCom, cepCom); Pessoa p = new Pessoa(nome, cpf, sexo, endRes, endCom); switch (tipo) { case 0: c = new Conta(numero, saldo, p); break; case 1: c = new ContaEspecial(numero, saldo, p, (int) limite); break; case 2: c = new Poupanca(numero, saldo, p, diaAniv); break; } } catch (SQLException e) { throw new RepositorioException(e.getMessage()); } if (c == null) throw new ContaInexistenteException(numero); return c; } public void atualizar(Conta conta) throws ContaInexistenteException, RepositorioException { procurar(conta.getNumero()); String sql = “UPDATE CONTA SET SALDO = ? WHERE (NUMERO = ?)“; PreparedStatement pstmt; try { pstmt = con.prepareStatement(sql); pstmt.setDouble(1, conta.getSaldo());68
  • 69. Programação III pstmt.setInt(2, conta.getNumero()); pstmt.executeUpdate(); } catch (SQLException e) { throw new RepositorioException(e.getMessage()); } }}public Conta[] getContas() throws RepositorioException { String sql = “SELECT NUMERO FROM CONTA”; List<Conta> contas = new ArrayList<Conta>(); Statement stmt; try { stmt = con.createStatement(); ResultSet rs = stmt.executeQuery(sql); while (rs.next()) { int num = rs.getInt(“NUMERO”); Conta c = procurar(num); contas.add(c); } rs.close(); stmt.close(); } catch (SQLException e) { throw new RepositorioException(e.getMessage()); } catch (ContaInexistenteException e) { } return (Conta[]) contas.toArray();}public void inserir(Conta conta) throws ContaJaCadastradaException, RepositorioException { try { procurar(conta.getNumero()); throw new ContaJaCadastradaException(conta); } catch (ContaInexistenteException e) { try { String sqlConsultaCPF = “SELECT * FROM PESSOA WHERE CPF = ?”; PreparedStatement pstmtConsultaCPF = con. prepareStatement(sqlConsultaCPF); System.out.println(conta.getCorrentista().getCpf()); pstmtConsultaCPF.setString(1, conta.getCorrentista().getCpf()); ResultSet rsConsultaCPF = pstmtConsultaCPF.executeQuery(); if (!rsConsultaCPF.next()) { throw new RepositorioException(“Erro de Integridade Referencial. CPF do correntista não cadastrado”); } rsConsultaCPF.close(); pstmtConsultaCPF.close(); String sqlConta = “INSERT INTO CONTA(NUMERO, TIPO, SALDO, CPF) VALUES (?,?,?,?)”; PreparedStatement pstmtConta = con.prepareStatement(sqlConta); con.setAutoCommit(false); 69
  • 70. Programação III pstmtConta.setInt(1, conta.getNumero()); int tipo = 0; if (conta instanceof ContaEspecial) { tipo = 1; } else if (conta instanceof Poupanca) { tipo = 2; } pstmtConta.setInt(2, tipo); pstmtConta.setFloat(3, conta.getSaldo()); pstmtConta.setString(4, conta.getCorrentista().getCpf()); pstmtConta.executeUpdate(); pstmtConta.close(); switch (tipo) { case 1: String sqlContaEspecial = “INSERT INTO CONTA_ESPECIAL(NUMERO, LIMITE) VALUES (?,?)”; PreparedStatement pstmtContaEspecial = con. prepareStatement(sqlContaEspecial); pstmtContaEspecial.setInt(1, conta. getNumero()); pstmtContaEspecial.setDouble(2, ((ContaEspecial) conta).getLimite()); pstmtContaEspecial.executeUpdate(); pstmtContaEspecial.close(); break; case 2: String sqlPoupanca = “INSERT INTO POUPANCA(NUMERO, DIA_ANIVERSARIO, TAXA_JUROS) VALUES (?,?,?)”; PreparedStatement pstmtPoupanca = con. prepareStatement(sqlPoupanca); pstmtPoupanca.setInt(1, conta.getNumero()); pstmtPoupanca.setInt(2, ((Poupanca) conta). getDiaAniversario()); pstmtPoupanca.setDouble(3, 10); pstmtPoupanca.executeUpdate(); pstmtPoupanca.close(); break; } con.commit(); con.setAutoCommit(true); } catch (SQLException e3) {try { if (con != null) con.rollback(); } catch (SQLException e1) { throw new RepositorioException(e.getMessage()); } throw new RepositorioException(e.getMessage()); }70
  • 71. Programação III }}public void remover(int numero) throws ContaInexistenteException, RepositorioException { Conta c = procurar(numero); try { con.setAutoCommit(false); String sql = null; PreparedStatement pstmt = null; if (c instanceof ContaEspecial) { sql = “DELETE FROM CONTA_ESPECIAL WHERE (NUMERO = ?) “; pstmt = con.prepareStatement(sql); pstmt.setInt(1, numero); pstmt.executeUpdate(); } if (c instanceof Poupanca) { sql = “DELETE FROM POUPANCA WHERE (NUMERO = ?) “; pstmt = con.prepareStatement(sql); pstmt.setInt(1, numero); pstmt.executeUpdate(); } sql = “DELETE FROM CONTA WHERE (NUMERO = ?) “; pstmt = con.prepareStatement(sql); pstmt.setInt(1, numero); pstmt.executeUpdate(); con.commit(); pstmt.close(); con.setAutoCommit(true); } catch (SQLException e) { throw new RepositorioException(e.getMessage()); }}public void transferir(int contaOrigem, int contaDestino, float valor) throws ContaInexistenteException, RepositorioException { procurar(contaOrigem); procurar(contaDestino); try { con.setAutoCommit(false); String sql = “UPDATE CONTA SET SALDO = SALDO - ? WHERE (NUMERO = ?) “; PreparedStatement pstmt; pstmt = con.prepareStatement(sql); pstmt.setDouble(1, valor); pstmt.setInt(2, contaOrigem); pstmt.executeUpdate(); sql = “UPDATE CONTA SET SALDO = SALDO + ? WHERE (NUMERO = ?) “; pstmt = con.prepareStatement(sql); pstmt.setDouble(1, valor); 71
  • 72. Programação III pstmt.setInt(2, contaDestino); pstmt.executeUpdate(); con.commit(); pstmt.close(); con.setAutoCommit(true); } catch (SQLException e) { try { con.rollback(); } catch (SQLException e1) { throw new RepositorioException(e.getMessage()); } throw new RepositorioException(e.getMessage()); } } } Ao criar a classe, o construtor já estabelece uma conexão com o SGBD. Para evitar que a conexão seja aberta e fechada o tempo todo, o objeto con representa a conexão que vai ser utilizada pela classe enquanto ela estiver ativa. Para isto, o método criarConexao() é definido, cuja função única é estabelecer a conexão com o banco. O método procurar é aquele que busca do banco as informações necessárias para se criar um objeto Conta. A busca é feito de acordo com o número da conta. Para se criar o objeto conta é necessário obter todas as informações necessárias para se criar um objeto Conta. Portanto, primeiramente é feita uma busca na tabela conta, procurando por algum registro cujo o número da conta seja igual àquele passado pelo método. Caso não seja encontrado, é levantada a exceção ContaInexistenteException. Caso contrário, as informações sobre o correntista e seus endereços são obtidas das tabelas PESSOA e ENDERECO, respectivamente. Se forem necessárias, informações adicionais devem ser obtidas das tabelas CONTA_ESPECIAL e POUPANCA. Quando todas as informações forem obtidas, é possível criar o objeto para retorno do método. É importante frisar que, de acordo com o tipo da conta, deve-se instanciar contas convencionais, especiais ou poupanças. O método procurar é reaproveitado por outros métodos, como o remover, atualizar, transferir ou mesmo o getContas. Isto porque todos estes métodos precisam verificar antes se uma ou mais contas existem para realizar atualizações nas tabelas. No caso do método remover, um cuidado especial é que deve-se utilizar transações para remover contas especiais e poupanças. Esta necessidade se dá porque a remoção deste tipo de conta requer que seja removidos registros de mais de uma tabela. Por isso, no início do método o modo de operação da conexão é modificada para autocommit false. No final do método, se por acaso forem necessários dois comandos DELETE, é feito um commit da transação. Procedimento semelhante é utilizado para a operação de transferir, onde são feitos duas atualizações, como já explicado anteriormente. No caso da operação de atualização, por questões de simplificação, o único campo que pode ser alterado de uma conta é o seu saldo. Em outras palavras, uma conta uma vez criada não pode mudar seu correntista ou tipo. Isto é uma restrição apenas para facilitar a compreensão deste exemplo. O método mais longo é o inserção de contas, o inserir. O método pega as informações do objeto conta repassado e realiza operações de inserção nas tabelas CONTA, CONTA_ESPECIAL (quando necessário) e POUPANCA (quando necessário). Para cadastrar uma conta, é necessário que as informações sobre o correntista e os endereços deste correntista já tenham sido cadastradas no banco. Isso remete a idéia que o sistema deve72
  • 73. Programação IIIfornece cadastros independentes para informações sobre pessoas e endereços, o queé um projeto comum nas aplicações atuais. Primeiro cadastra-se as informações menosdependentes para depois as mais dependentes. Logo, ao se cadastrar uma conta, verifica-sese existe na tabela PESSOA se existe um registro com o cpf do correntista do objeto Conta.Caso isso não ocorra, é levantada uma exceção RepositorioException, com a descrição deerro de integridade referencial. Se não houver problemas, são realizados operações deinserção nas tabelas relativas a dados de contas. Novamente nestes casos, estas inserçõessão tratadas como transações, deixando para o programador a responsabilidade de efetivara inclusão dos registros ao final do método. A alteração para utilização de SGBD requer também que alterações sejam feitas emoutras classes. A classe que utiliza o conjunto de contas, por exemplo, realiza operações queprecisam ser efetivadas na base. Tome como exemplo a operação de debitar, listada a seguir private ConjuntoContas conjunto = new ConjuntoContasDB(); public void atualizar(Conta conta) throws ContaInexistenteException, RepositorioException { conjunto.atualizar(conta); } public void debitar(int numero, float valor) throws SaldoInsuficienteException, ContaInexistenteException, RepositorioException { Conta c = procurar(numero); if (c != null) { c.debitar(valor); atualizar(c); } } Veja que a realização da operação de débito é feita apenas no objeto Conta. Logo,para que sua modificação seja também realizada no banco, é necessário atualizar a conta.Isto é válido para todas aquelas operações que anteriormente eram realizadas apenas nosobjetos em memória. Exercícios 1. O Diagrama de classes abaixo representa os conceitos para o sistema de controle de mídias do capítulo 2. 73
  • 74. Programação III Para um sistema em Java que controle a persistência dos dados, 3 interfaces foram projetadas: public interface ConjuntoCantor { // Insere um cantor na base de dados public void inserir(Cantor cantor); // Retorna um objeto que representa o cantor, baseado no código do mesmo public Cantor procurar(int numero) throws CantorInexistenteException; // Retorna um objeto que representa o cantor, baseado no nome do mesmo public Cantor procurar(String nome) throws CantorInexistenteException; } public interface ConjuntoMusica { // Insere uma música na base public void inserir(Musica musica); // Permite alterar o nome e o tempo de uma música na base public void atualizar(Musica musica) throws MusicaInexistenteException; // Retorna um objeto que representa uma música, baseado no código da mesma public Musica procurar(int numero) throws MusicaInexistenteException; } public interface ConjuntoMidia { // Insere uma música na base public void inserir(Midia midia); //Remove uma mídia e todas as suas músicas da base public void remover(int numero) throws MidiaInexistenteException; //Retorna uma mídia da base, de acordo com seu número public Midia procurar(int numero) throws MidiaInexistenteException; } De acordo com as interfaces e o diagrama de classes apresentados, implemente versões para persistência das informações utilizando o banco de dados HyperSQL. Baseie-se no exemplo apresentado no final deste capítulo para realizar este exercício. Vamos Revisar?74
  • 75. Programação III Resumo Neste último capítulo, vimos como é possível integrar nossos programas com basesde dados, por meio da API JDBC. Atualmente, existem abordagens mais flexíveis e queprocuram deixar o mapeamento entre objetos e tabelas mais transparente. A especificaçãoJPA (Java Persistence API) é a principal referência para a modelagem objeto-relacional naatualidade. Com os conhecimentos iniciados neste volume, você tem toda uma base que lheservirá para estudos mais avançados sobre a integração entre SGBDs e sistemas orientadosa objetos. 75
  • 76. Programação III Conheça o Autor Fernando Trinta Sou professor de ciência de computação, formado pela Universidade Federal do Maranhão. Tenho Mestrado e Doutorado em Ciência da Computação pelo Centro de Informática da Universidade Federal de Pernambuco, com ênfase na área de Sistemas Distribuídos. Durante minha pós-graduação, estive envolvido com os temas de objetos distribuídos e educação à distância no Mestrado, e jogos digitais, middleware e computação ubíqua no Doutorado. Trabalhei no desenvolvimento de sistemas em várias empresas, privadas e públicas. Atualmente faço parte do corpo docente do Centro de Informática da Universidade Federal de Pernambuco. Além da informática, gosto muito de esportes em geral e cinema. Mas nos últimos anos, duas novas paixões tomaram conta do meu mundo: Ian e Ananda.76