prevalência – persistência transparente de objetos em memória

Propaganda
UNIVERSIDADE PRESBITERIANA MACKENZIE
CARLOS ALBERTO LINS GONÇALVES DOS SANTOS
LUIZ EDUARDO DE FRANCO MACEDO
MARCELO ROSIN CITRANGULO
MARCO AURELIO GIOVANI VISCONTI
PREVALÊNCIA – PERSISTÊNCIA TRANSPARENTE DE
OBJETOS EM MEMÓRIA
São Paulo
2003
CARLOS ALBERTO LINS GONÇALVES DOS SANTOS
LUIZ EDUARDO DE FRANCO MACEDO
MARCELO ROSIN CITRANGULO
MARCO AURELIO GIOVANI VISCONTI
PREVALÊNCIA – PERSISTÊNCIA TRANSPARENTE DE
OBJETOS EM MEMÓRIA
Trabalho apresentado à disciplina de
Trabalho de Graduação Interdisciplinar II,
como parte das exigências para a obtenção
do título de Bacharel em Sistemas de Informação
pela Faculdade de Computação e Informática
da Universidade Presbiteriana Mackenzie
ORIENTADOR: ROGÉRIO DE OLIVEIRA
São Paulo
2003
SUMÁRIO
RESUMO ............................................................................................
ABSTRACT ..........................................................................................
1 – INTRODUÇÃO .....................................................................................
2 – CONCEITOS .......................................................................................
2.1 – SISTEMA GERENCIADOR DE BANCO DE DADOS ........................................ 12
2.1.1 – Sistemas Gerenciadores de Bancos de Dados Relacionais............................... 13
2.1.2 – Sistemas Gerenciadores de Bancos de Dados Orientados a Objeto ................. 16
2.2 – CARACTERÍSTICAS DE UM SGBD ................................................................... 18
2.2.1 – Gerenciamento de Transações .......................................................................... 18
2.2.2 – Serialização....................................................................................................... 21
2.2.3 – Controle de Concorrência................................................................................. 22
2.2.4 – Recuperação...................................................................................................... 22
2.2.5 – Log de Transação.............................................................................................. 22
2.3 – CARACTERÍSTICAS DE UM SGBDOO.............................................................. 24
2.3.1 – Objetos Complexos .......................................................................................... 24
2.3.2 – Identificador de Objetos ................................................................................... 25
2.3.3 – Encapsulamento................................................................................................ 26
2.3.4 – Tipos ou classes ................................................................................................ 27
2.3.5 – Herança............................................................................................................. 28
2.3.6 – Acoplamento tardio (late binding).................................................................... 29
2.3.7 – Completeza Computacional.............................................................................. 30
2.3.8. – Extensibilidade ................................................................................................ 31
2.3.9 – Persistência de Objetos..................................................................................... 32
2.3.10 – Capacidade de gerenciamento de armazenamento secundário....................... 33
2.3.11 – Capacidade de prover concorrência................................................................ 33
2.3.12 – Recuperação.................................................................................................... 33
2.3.13 – Consulta simples de dados (queries “ad hoc”) ............................................... 33
2.4 – PERSISTÊNCIA ..................................................................................................... 34
2.4.1 – Persistência Ortogonal...................................................................................... 35
2.5 – LINGUAGENS DE PROGRAMAÇÃO PERSISTENTES .................................... 36
2.6 – INCOMPATIBILIDADE DE IMPEDÂNCIAS (IMPEDANCE MISMATCH).... 37
3 – SISTEMAS PREVALENTES ..........................................................................
3.1 – BREVE HISTÓRICO.............................................................................................. 39
3.2 – DEFINIÇÕES DE PREVALÊNCIA....................................................................... 39
3.3 – ESQUEMA GERAL DE FUNCIONAMENTO DA PREVALÊNCIA.................. 42
3.4 – IMPLEMENTAÇÕES: PREVAYLER E BAMBOO.PREVALENCE .................. 49
3.5 – VANTAGENS E DESVANTAGENS DA PREVALÊNCIA................................. 52
3.5.1 – Eliminação da tecnologia relacional................................................................. 52
3.5.2 – Ambiente unificado .......................................................................................... 54
3.5.3 – Representação única da solução ....................................................................... 55
3.5.4 – Armazenamento em memória........................................................................... 57
3.6 – APLICAÇÕES POTENCIAIS DE SISTEMAS PREVALENTES......................... 57
4 – IMPLEMENTAÇÃO .................................................................................
4.1 – PRÉ-REQUISITOS ................................................................................................. 59
4.2 – DESENHO DA APLICAÇÃO................................................................................ 60
4.3 – AMBIENTE WEB................................................................................................... 62
4.4 – ADICIONANDO A PREVALENCIA AO MODELO ........................................... 63
4.5 – IMPLEMENTANDO A PREVALÊNCIA.............................................................. 65
4.6 – MANIPULANDO OBJETOS PERSISTENTES .................................................... 68
4.6.1 – Inclusão............................................................................................................. 69
4.6.2 – Consulta............................................................................................................ 72
4.6.3 – Alteração........................................................................................................... 74
4.6.4 – Exclusão ........................................................................................................... 77
4.7 – DESEMPENHO ...................................................................................................... 79
5 – CONCLUSÃO ......................................................................................
6 – REFERÊNCIAS BIBLIOGRÁFICAS ................................................................
7 – BIBLIOGRAFIA COMPLEMENTAR ................................................................
INDÍCE DE FIGURAS
Figura 1 - Modelo Entidade Relacionamento de um sistema de Banco de Dados............... 14
Figura 2 - Sistema Gerenciador de Banco de Dados Orientado a Objeto. ........................... 17
Figura 3 - Serialização da execução de duas transações. ..................................................... 21
Figura 4 - Representação gráfica do conceito de encapsulamento....................................... 27
Figura 5 – Diagrama UML representando herança de classes. ............................................ 29
Figura 6 - Relação de inventário com tipo de dado pré-determinado. ................................. 30
Figura 7 - Classe inventário com acoplamento prévio. ........................................................ 30
Figura 8 - Classe inventário com acoplamento tardio. ......................................................... 30
Figura 9 - Serialização do estado de um objeto.................................................................... 43
Figura 10 - Diagrama temporal do início de execução de um sistema prevalente. .............. 45
Figura 11 - Diagrama temporal de um sistema prevalente em funcionamento. ................... 48
Figura 12 – Arquivo XML que representa a alteração da estrutura de um objeto. .............. 50
Figura 13 - Três mapeamentos com duas representações da solução................................... 55
Figura 14 - Um único mapeamento representando a solução............................................... 56
Figura 15 - Modelo de objetos.............................................................................................. 61
Figura 16 - Ambiente de uma aplicação web. ...................................................................... 63
Figura 17 - Modelo de objetos com suporte à prevalência................................................... 64
Figura 18 - Objetos persistentes e transientes. ..................................................................... 67
Figura 19 - Diagrama de sequência da inclusão de um objeto persistente. .......................... 71
Figura 20 - Diagrama de sequência da consulta de um objeto persistente ........................... 74
Figura 21 - Diagrama de sequência de alteração de um objeto persistente.......................... 77
Figura 22 - Diagrama de sequência de exclusão de um objeto persistente. ......................... 79
INDÍCE DE TABELAS
Tabela 1 – Bancos de Dados Orientados a Objeto e de seus respectivos fornecedores. ...... 17
Tabela 2 - Características Mandatórias e Opcionais de um SGBDOO. ............................... 24
Tabela 3 – Tempos de duração dos valores de dados........................................................... 34
Tabela 4 – Implementações da prevalência em diversas linguagens.................................... 51
Tabela 5 - Resultados dos testes de desempenho. ................................................................ 80
INDÍCE DE EXEMPLOS DE CÓDIGO
Exemplo 1 - Serialização automática com o uso do atributo [Serializable]......................... 65
Exemplo 2 - A função Application_Start ............................................................................. 66
Exemplo 3 - Criação do objeto engine. ................................................................................ 66
Exemplo 4 - Criação do objeto raiz da persistência. ............................................................ 66
Exemplo 5 - Adicionando objetos ao contexto da aplicação................................................ 67
Exemplo 6 - Exemplo de uma classe de comando. .............................................................. 68
Exemplo 7 - Exemplo de uma classe de consulta................................................................. 69
Exemplo 8 - Exemplo de uma classe de inclusão................................................................. 69
Exemplo 9 - Código que invoca o comando que torna o objeto persistente. ....................... 70
Exemplo 10 - Código que cria uma classe de consulta. ....................................................... 73
Exemplo 11 - Código que invoca uma classe de consulta.................................................... 73
Exemplo 12 - Código da classe de alteração do objeto Course. .......................................... 75
Exemplo 13 - Código de alteração da classe Course. .......................................................... 75
Exemplo 14 - Código da classe de comando que remove o objeto do tipo Course. ............ 78
Exemplo 15 - Código cliente que chama o comando que remove o objeto do tipo Course.78
RESUMO
O objetivo deste estudo é analisar e demonstrar a utilização da prevalência no
desenvolvimento de sistemas orientados a objeto como alternativa para a persistência de
dados. A prevalência é conceituada e seu uso é comparado aos principais sistemas que
fornecem o serviço de persistência de dados, como os bancos de dados relacionais e
orientados a objeto. Um esquema geral do funcionamento da prevalência é abordado a fim
de fornecer um melhor entendimento desse modelo de persistência de objetos. As
vantagens e desvantagens, assim como os requisitos que melhor são atendidos quando da
utilização da prevalência, como camada de persistência de objetos, são também descritos.
Na parte prática do estudo, implementou-se um sistema orientado a objeto
utilizando a prevalência para persistir objetos. A partir desse sistema, executaram-se testes
para avaliar e discutir questões como o espaço de armazenamento e o desempenho da busca
de objetos. Todas as informações apresentadas sobre a prevalência neste estudo têm como
propósito auxiliar o leitor a verificar se este modelo é a escolha mais adequada para o
fornecimento do serviço de persistência no desenvolvimento de sistemas orientados a objeto.
ABSTRACT
The goal of this research is analyzing and demonstrating the using of the prevalence
at the development of object-oriented systems as an alternative for data persistence. The
concepts concerning the prevalence are shown. The using of prevalence is compared to the
main systems providing the service of data persistence, such as relational and objectoriented databases. A general schema of prevalence´s working is approached in order to
provide a better understanding about this object persistence model. There is a description
about all advantages and disadvantages using the prevalence, as well the requirements met
at the using of prevalence, such as the object persistence layer.
At the practical part of this research, it was implemented an object-oriented system
by using the prevalence to persist objects. It were performed tests based on this system in
order to evaluate and to discuss issues, such as storage space and the performance of object
search. All information provided at this research about prevalence are driven to help the
reader to verify that this model is the best choice for providing a persistence service at the
development of object-oriented systems.
1 – INTRODUÇÃO
A persistência é uma característica fundamental para o armazenamento de objetos,
permitindo que perdurem para serem recuperados posteriormente. Na maioria dos casos, a
persistência é alcançada através de sistemas gerenciadores de banco de dados relacionais que,
para proverem o serviço de persistência, requerem adequações do modelo relacional e do
sistema orientado a objeto.
Alternativas de modelos de persistência têm sido estudadas para tentar superar os
problemas causados por essas adaptações, dentre elas pode-se citar os sistemas gerenciadores
de banco de dados orientados a objeto e as linguagens de programação persistentes. Um
modelo emergente de adicionar persistência aos sistemas orientados a objeto é a prevalência.
A prevalência é um modelo transparente de persistência de objetos baseado no
armazenamento dos objetos na memória principal do computador, característica que a
diferencia dos sistemas convencionais.
Este trabalho encontra-se organizado como segue. O Capítulo 2 abrange conceitos
relacionados à persistência e sistemas que fornecem esse serviço, como gerenciadores de
banco de dados relacionais e orientados a objeto, e suas principais características. Os sistemas
gerenciadores de banco de dados orientados a objeto são tratados com maior detalhe, pois
conceitualmente trazem maiores semelhanças com os sistemas prevalentes do que os
relacionais, sobretudo pelo uso de objetos. Finalmente, a incompatibilidade de impedâncias é
descrita para ilustrar o problema da utilização de bancos de dados relacionais como camada
de persistência em sistemas orientados a objeto.
O Capítulo 3 trata do conceito de prevalência. O funcionamento desse sistema, as
principais implementações e as aplicações. Ressaltam-se as vantagens e as desvantagens dos
10
sistemas prevalentes quando comparados com os sistemas gerenciadores convencionais
(relacional e orientado a objeto).
No Capítulo 4, exemplifica-se um sistema prevalente através de uma implementação
baseada em código aberto.
11
2 – CONCEITOS
2.1 – SISTEMA GERENCIADOR DE BANCO DE DADOS
Um banco de dados, ou um sistema de banco de dados, pode ser definido como um
depósito contendo um conjunto de arquivos de dados, objetivando, o armazenamento, a
disponibilização de informações e a manutenção. Envolve quatro componentes principais:
hardware, software, dados e usuários [Date, 1991].
Adicionando ao conjunto de arquivos, uma série de programas que fornecem um
ambiente conveniente e eficiente para recuperar e armazenar informações, tem-se um Sistema
Gerenciador de Banco de Dados (SGBD) [Silberschatz, 1999].
O SGBD provê segurança para os dados armazenados e são projetados para o
gerenciamento de grandes volumes de informação de natureza persistente, permitindo
operações eficientes sobre esses dados.
Os SGBDs mostram-se superiores em comparação aos sistemas de arquivos,
fornecendo maior facilidade de acesso aos dados, melhor segurança, integridade, minimização
da redundância e acessos concorrentes mais estáveis. Apresentam ainda as propriedades
essenciais de atomicidade, consistência, isolamento e durabilidade (propriedades ACID).
Os SGBDs buscam fornecer maior transparência no acesso aos dados. Segundo
[Silberschatz, 1999], a proposta maior é prover aos usuários uma visão abstrata dos dados,
isto é, o sistema omite certos detalhes de como os dados são armazenados e mantidos. Desta
forma, a complexidade está escondida dos usuários através de diversos níveis de abstração
que simplificam a interação do usuário com o sistema.
12
Um gerenciador pode administrar mais de um banco de dados, por exemplo, uma
faculdade pode possuir um banco de dados para o controle de seus alunos e um outro banco
de dados para os livros de sua biblioteca e diferentes usuários podem acessar tais bancos
através do mesmo SGBD.
2.1.1 – Sistemas Gerenciadores de Bancos de Dados Relacionais
Apesar da história relatar outros modelos de banco de dados (o modelo de rede e
também o modelo hierárquico), o modelo relacional foi um dos primeiros a serem utilizados
com grande sucesso nas aplicações comerciais.
O nome desse modelo de dados vem dos conceitos matemáticos de relações e de
conjuntos. Nesse modelo, as informações que identificam uma determinada entidade (ou
objeto) do mundo real são armazenadas em um formato tabular (relações), onde a tabela é o
produto da intersecção entre linhas (ou tuplas) e colunas. Pode-se representar uma entidade do
mundo real em uma tabela ou em diversas tabelas. Uma linha é a representação de uma
entidade e a tabela é composta por um conjunto de entidades.
Considere-se uma entidade “aluno”, com os atributos Nome, Endereço, CPF, RG e
Matrícula. Esses atributos são as colunas da tabela “aluno” e cada um dos alunos de uma
determinada entidade de ensino são as linhas desta mesma tabela.
Cada dado deve ser identificado e transformado em atributos, os quais formam as
colunas dessa tabela, enquanto cada linha representa uma entidade, identificando os diversos
objetos desse tipo que fazem parte do sistema [Silberschatz, 1999] [Rob e Coronel, 1995].
Existem vários métodos e técnicas para modelar os objetos do mundo real e
representá-los em tabelas, para que os mesmos possam ser armazenados em um sistema de
13
banco de dados relacional, que só “entende” relações. Neste trabalho, entretanto, é suficiente
considerar apenas os conceitos já descritos.
Figura 1 - Modelo Entidade Relacionamento de um sistema de Banco de Dados.
As interações que são realizadas com um banco de dados dependem do sistema e da
necessidade da aplicação. É necessário ainda, que exista, uma linguagem de consulta para as
diferentes possibilidades de interação desejadas.
Dependendo da necessidade, a manipulação dos dados pode ser implementada em uma
linguagem de consulta do tipo procedural ou não-procedural ou, até mesmo, utilizando os dois
tipos de linguagens.
Apesar de existirem outras linguagens de consulta, a mais usual nos bancos de dados
relacionais é a Structured Query Language (SQL). É uma linguagem padronizada para acesso
a dados, permitindo, além da consulta ao banco de dados, a definição das estruturas e
14
manipulação dos dados, assim como, a especificação de restrições de segurança para acesso
ao banco de dados.
Com a evolução tecnológica, a difusão das redes e a utilização do computador em
diversas áreas, surgiram muitos tipos de dados. Novas aplicações foram desenvolvidas com
características diversas, como exemplo, as aplicações multimídia com dados do tipo áudio,
imagem, vídeo etc., que demandam o armazenamento e a manipulação desses tipos de dados e
outros mais complexos.
Os bancos de dados relacionais não são tão capazes de lidar com os tipos de dados que
essas novas aplicações exigem [Silberschatz, 1999] e surgem, então, novas alternativas.
15
2.1.2 – Sistemas Gerenciadores de Bancos de Dados Orientados a
Objeto
Devido às limitações do modelo relacional de dados no tratamento das novas
aplicações, vários modelos de dados foram e estão sendo propostos. Entre eles, o modelo
orientado a objeto [Silberschatz, 1999].
Na busca de dar suporte a novas tecnologias e aplicações integradas abrangendo dados
multimídia (imagens, gráficos, dados de voz e vídeo), objetos espaciais com estrutura gráfica,
dados de experimentos científicos, de telecomunicações, de sistemas de informação
geográfica etc., surgiu o Banco de Dados Orientado a Objeto.
Um Banco de Dados Orientado a Objeto (BDOO) busca armazenar dados de natureza
complexa, como os dados de aplicações de Engenharia de Software Auxiliada por
Computador (CASE), de Desenho Auxiliado por Computador (CAD), de Manufatura
Auxiliada por Computador (CAM) e de Sistemas de Informação de Escritório (OIS).
Os Bancos de Dados Orientados a Objeto apenas se tornaram realidade a partir do
desenvolvimento das linguagens de programação orientadas a objeto.
Na programação orientada a objeto os programas podem conter, além dos tipos de dados
tradicionais (string, inteiro, float etc), as chamadas classes, que são uma extensão dos tipos de
dados tradicionais e, também, podem conter procedimentos (métodos) que definem o quê e como
podem ser realizadas as operações com esses objetos (comportamento dos objetos).
Os dados dos programas criados com a linguagem orientada a objeto são armazenados
em objetos durante a execução do programa [Nassu e Setzer, 1999].
16
Os Sistemas Gerenciadores de Bancos de Dados Orientados a Objeto (SGBDOOs)
utilizam as características da linguagem de programação orientada a objeto, em conjunto com
as características de um sistema de banco de dados convencional [Khoshafian, 1994].
Figura 2 - Sistema Gerenciador de Banco de Dados Orientado a Objeto.
Comercialmente, começam a surgir por volta dos anos 80. A tabela 1 traz alguns
exemplos de protótipos e produtos comerciais de SGBDOO e seus respectivos fornecedores.
Banco de Dados
Orientado a Objeto
ORION
OPENOOBB
IRIS
ODE
ENCORE/OB
OBJECTIVITY
JASMINE
Empresa/universidade
Microelectronics and Computer Technology Corporation
Texas Instruments
Hewlett Packard laboratories
AT & T Bell Labs
Server Brown University
Objectivity Inc
Computer Associates (CA)
Tabela 1 – Bancos de Dados Orientados a Objeto e de seus respectivos fornecedores.
Os BDOOs integram duas tecnologias: a de banco de dados e a de orientação a objeto.
Portanto, trazem a combinação dos benefícios dos conceitos da orientação a objeto com a
funcionalidade dos bancos de dados [Khoshafian, 1994].
17
2.2 – CARACTERÍSTICAS DE UM SGBD
A seguir são abordadas algumas das principais características dos SGBDs, como
gerenciamento de transações, serialização, controle de concorrência, recuperação e log de
transação.
2.2.1 – Gerenciamento de Transações
A realização de atividades dentro de uma aplicação é executada por operações que,
normalmente, constituem uma unidade lógica de trabalho. “A transação desempenha uma
função lógica e é composta por uma coleção de operações” [Silberschatz, 1999].
Transações representam eventos do mundo real, como por exemplo a venda de
produtos ou o depósitos de valores em conta. Executar e gerenciar transações são importantes
atividades dos sistemas gerenciadores de banco de dados. Uma transação pode consistir de
uma simples busca para gerar uma lista de conteúdos de tabela ou pode consistir de uma série
de comandos seqüenciais.
Por exemplo, para realizar uma atividade de transferência de fundos bancários (uma
única unidade lógica de trabalho – uma transação), várias operações são executadas. Para citar
algumas:
•
Quando o valor sai de uma determinada conta, uma operação de subtração
deve ser realizada, assim como a atualização desse saldo;
•
Quando o valor entra na conta de destino, uma operação de soma deve ser
realizada, assim como a atualização de saldo desta conta também.
18
Esse exemplo simples demonstra que a atividade realizada por uma transação, pode
ser composta por diversas operações diferentes.
As principais propriedades que um SGBD deve prover a uma transação são conhecidas
como propriedades ACID e são:
•
Atomicidade;
•
Consistência;
•
Isolamento;
•
Durabilidade.
O conceito de Atomicidade (da propriedade ACID) refere-se ao fato da necessidade da
transação ser atômica, ou seja, não se pode dividir as operações que a compõe, ou todas as
operações que compõe a transação são efetuadas por completo ou nenhuma será.
A Consistência é outra propriedade (ACID) importante. Se o banco de dados está
inicialmente consistente, a execução de uma transação deve levar o banco de dados a outro
estado também consistente.
As diferentes operações que compõem uma transação podem ser executadas por
programas e/ou rotinas diferentes. Esses programas executados isoladamente levam a uma
inconsistência dos dados em um determinado instante, obrigando o sistema de banco de dados
a manter a consistência dos dados após a execução de todos os programas que compõem a
transação.
Usando o mesmo exemplo anterior de transferência de fundos entre contas, esse
conceito ficará mais claro. Na transação de transferência executada, dois programas distintos,
19
um para débito em conta e outro para crédito em conta são executados isoladamente um após
o outro.
Após a execução do programa de débito e antes da execução do programa de crédito, o
banco de dados estará em um estado de inconsistência, pois neste instante é como se o fundo
da conta de origem tivesse desaparecido sem motivo. Após a execução do programa de
crédito na conta de destino o banco de dados deverá voltar ao estado de consistência anterior a
execução da transação. O resultado final coincide com o inicial, ou seja, o resultado da soma
dos saldos da conta origem e destino deverá ser o mesmo antes e depois da transação, pois o
valor que saiu de uma conta entrou na outra.
No instante em que a transação de transferência de fundos entre contas estiver em
execução, diversas operações serão realizadas com os dados das contas e nenhuma outra
transação poderá alterar os dados dessa(s) conta(s) antes da transação de transferência
terminar, ou seja, uma transação deve ser executada isoladamente (separadamente) de outra
que acessa os mesmos dados.
Os bancos de dados também devem ter mecanismos para manter a consistência dos
dados, mesmo no caso em que falhas de software ou hardware ocorram, e devem também,
permitir a execução de transações de forma concorrente. “A execução simultânea de
transações proporciona uma melhoria de desempenho significativa” [Silberschatz, 1999].
Neste aspecto, o conceito de Isolamento (da propriedade ACID) torna-se muito
importante em um sistema de banco de dados, no intuito de não permitir que os dados possam
ficar inconsistentes devido às transações concorrentes, havendo a necessidade de mecanismos
de isolamento de transações adequados.
20
A propriedade que garante a persistência dos dados, é a Durabilidade (ACID). Após a
execução com sucesso de uma transação, os dados devem ser persistidos, ou seja, gravados
em um meio físico de armazenamento não volátil, pois caso haja uma falha de energia, por
exemplo, os dados poderão ser recuperados para utilização posterior.
2.2.2 – Serialização
A fim de conseguir um maior nível de isolamento, muitos sistemas de banco de dados
implementam a chamada serialização, onde as transações concorrentes são tratadas como se elas
fossem executadas em ordem serial (uma após a outra), conforme demonstrado na figura 3. Desta
forma, somente uma única transação está ativa de cada vez. Essa propriedade é importante,
tanto em banco de dados multiusuários como distribuídos, onde muitas transações são
executadas concorrentemente.
Figura 3 - Serialização da execução de duas transações.
21
2.2.3 – Controle de Concorrência
O SGBD deve controlar a interação entre as transações concorrentes a fim de não
prejudicar a consistência. Tal controle é feito através de uma diversidade de mecanismos: os
esquemas de controle de concorrência.
Vários esquemas de controle de concorrência agem atrasando uma operação ou abortando
a transação, buscando assegurar a serialização. Para tanto, algumas técnicas para controle são
utilizadas, tais como: protocolos de bloqueio (lock); ordenação por registro de tempo (timestamp),
técnicas de validação, granularidade múltipla e multiversão [Silberschatz, 1999].
2.2.4 – Recuperação
As possíveis falhas que podem ocorrer em um banco de dados (falhas de transação, de
sistema ou meio) podem gerar um estado inconsistente. Desta forma, cabe a um sistema de
banco de dados possuir um esquema de recuperação para detectar tais falhas e, caso ocorram,
recuperar as informações pertinentes, retornando o banco de dados a um estado consistente,
anterior à falha.
O SGBD deve garantir, através dos esquemas de recuperação, que as propriedades de
atomicidade e durabilidade sejam preservadas, mesmo com a possibilidade de falhas
[Silberschatz, 1999]. Uma das formas usuais de se realizar a recuperação é através do
mecanismo de log de transação.
2.2.5 – Log de Transação
Um log de transação mantém as informações de todas as transações que atualizaram os
dados em um sistema de banco de dados. Tais informações são utilizadas pelo sistema quando
22
ocorrer uma falha do próprio sistema, seja hardware ou software, términos anormais etc. A
restauração de um sistema de banco de dados corrompido torna-se facilitada através do uso do
log de transação.
O log de transação armazena os dados que participam da transação antes e depois da
mesma ser executada, além de algumas das tabelas, tuplas, e valores de atributos. O começo e
o fim (COMMIT) da transação também são gravados [Rob e Coronel, 1995].
A fim de que os registros de log sejam úteis na recuperação após falhas de sistema e
disco, o log deve residir em armazenamento estável (disco rígido) [Silberschatz, 1999].
23
2.3 – CARACTERÍSTICAS DE UM SGBDOO
Um Sistema Gerenciador de Banco de Dados Orientado a Objeto (SGBDOO) contém
características da orientação a objeto e de um sistema gerenciador de banco de dados. As
características mandatórias e opcionais são demonstradas na tabela 2 [Atkinson, 1989]:
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
1.
2.
3.
I. CARACTERÍSTICAS MANDATÓRIAS DE UM SGBDOO
A. ORIENTAÇÃO A OBJETOS
Suporte a objetos complexos.
Suporte a Identificador de Objetos (OID).
Objetos devem ser encapsulados.
Suporte a tipos ou classes.
Suporte à herança.
Acoplamento tardio.
Completeza computacional.
Extensibilidade.
B. SGBD
Persistência.
Capacidade de armazenamento secundário.
Capacidade de prover concorrência.
Capacidade de recuperar falhas de software e hardware (recuperação).
Consulta simples de dados (queries “ad hoc”).
II. CARACTERÍSTICAS OPCIONAIS
Suporte à herança múltipla.
Suporte a banco de dados distribuídos.
Versionamento.
Tabela 2 - Características Mandatórias e Opcionais de um SGBDOO.
A seguir serão abordadas com detalhes as características mandatórias relacionadas à
orientação a objeto e ao SGBD.
2.3.1 – Objetos Complexos
Os objetos que contêm outros objetos são chamados de objetos compostos ou
complexos, incorrendo em uma hierarquia de composição de objetos. Em determinadas
aplicações, um objeto pode participar na composição de muitos objetos.
24
Uma das principais motivações que contribuiu para o desenvolvimento de sistemas de
banco de dados orientados a objeto, está relacionada com a dificuldade que sistemas de banco
de dados tradicionais têm em representar objetos complexos como imagens, sons, vídeos etc.
Há dois tipos de objetos complexos: o estruturado e o não-estruturado. Um objeto
complexo estruturado é feito através da composição de elementos, definido através da aplicação
de tipos de construtores sobre objetos mais simples ou primitivos (string, float, double etc.) de
forma recursiva em vários níveis. Um objeto não-estruturado, tipicamente, é um tipo de dado
que requer uma grande quantidade de armazenamento, tais como os tipos de dados que
representam uma imagem ou um objeto de texto longo [Elmarsi e Navathe, 2000].
Sets, bags, rows, lists, arrays são exemplos de construtores. O conjunto mínimo de
construtores de um sistema é representado por sets (coleções do mundo real), lists ou arrays
(captam a ordem que ocorre no mundo real e têm uso em aplicações científicas) e tuplas
(representam as propriedades de uma entidade). Esses construtores devem ser ortogonais a
ponto de serem aplicados a qualquer objeto [Atkinson, 1989].
2.3.2 – Identificador de Objetos
Quando se cria um objeto, ele recebe um identificador que o diferencia de todos os
demais objetos durante sua existência. Nas linguagens orientadas a objeto essa identificação é
representada por ponteiros.
Como os ponteiros são endereços de memória, eles resolvem muito bem o problema
da identificação dos objetos em uma linguagem de programação, porque duram enquanto o
programa estiver em execução.
25
Por outro lado, nos SGBDOOs, essa abordagem não pode ser utilizada, pois é
necessário que os objetos tenham um tempo de vida maior do que o tempo de execução da
aplicação, ou seja, quando a aplicação for executada novamente ela precisa se referenciar a
um identificador do objeto que não seja o endereço de memória, devido a sua volatilidade,
para poder recuperar o objeto.
A identidade do objeto organiza e localiza os objetos no espaço de execução do
programa (memória).
Entre as diversas formas de representar a identidade do objeto, pode-se destacar a
forma em que é atribuído automaticamente um identificador pelo sistema quando o objeto é
criado. Esta forma está embutida no modelo de dados ou na linguagem de programação e é
usada nos sistemas de orientação a objeto.
2.3.3 – Encapsulamento
Na orientação a objeto, a comunicação dos objetos é feita através da troca de mensagens
entre os mesmos. Um objeto (emissor) envia uma mensagem para um outro objeto (receptor) a
fim de invocar um método do mesmo. A estrutura interna do receptor não pode ser acessada
diretamente pelo emissor, somente através de serviços (métodos) disponibilizados pelo receptor.
Esse impedimento assegura a integridade do estado do objeto ocultando os detalhes internos do
mesmo, caracterizando o encapsulamento do objeto.
O encapsulamento significa também que somente os aspectos públicos de um objeto
são vistos, enquanto que os detalhes de implementação são ocultos [Rob e Coronel, 1995].
26
MÉTODO 1
MÉTODO 2
DADOS
MÉTODO 3
MÉTODO 4
Figura 4 - Representação gráfica do conceito de encapsulamento.
2.3.4 – Tipos ou classes
Existem duas categorias principais de sistemas orientados a objeto:
•
suportados por tipos;
•
suportados por classes.
Os tipos se relacionam com os tipos de dados abstratos (ADTs -Abstract Data Types),
constituindo-se de objetos com características semelhantes. Possuem duas partes:
•
a interface – trata-se da parte visível ao usuário e consiste de uma lista de
operações juntamente com suas assinaturas;
•
a implementação – é visível apenas ao desenvolvedor , sendo formada por
dados de diferentes níveis de complexidade e por operações responsáveis por
implementar as outras operações relacionadas à interface.
Os tipos são utilizados em tempo de compilação para a checagem de erros dos programas
e não podem ser modificados em tempo de execução [Rob e Coronel, 1995].
As classes, assim como os tipos, são constituídos por objetos que possuem as mesmas
mensagens, os mesmos métodos e variáveis com mesmo nome e tipo. Desta maneira, os
27
objetos de uma classe são chamados instâncias desta classe. Todavia, as classes são utilizadas
para manipular objetos em tempo de execução.
2.3.5 – Herança
Conceito no qual uma classe é definida herdando todas as variáveis de instância e
métodos de uma classe já existente, adicionando novas variáveis e métodos que diferenciam
esta nova classe da existente.
Para estabelecer uma hierarquia de classes, é necessário realizar um estudo analítico
das classes identificadas, para determinar quais as classes que são potencialmente indicadas
para participarem da hierarquia. Após a determinação dessas classes deve-se dividir as
variáveis (mesmo nome e tipo), e os métodos e alocá-los em uma outra classe, estabelecendo
a hierarquia de classes. Nessa hierarquia de classes, as classes onde foram efetuadas as
divisões de variáveis e métodos são chamadas de subclasses e as classes que receberam as
variáveis e os métodos em comum são chamadas superclasses.
Em uma hierarquia de classes que possui N níveis, ao identificar a estrutura das
classes (todo o caminho que “liga” classes de um nível mais alto (superclasse) até uma classe
presente em um nível mais baixo (subclasse)), o compilador executa a herança, isto é, a
subclasse herda todas as variáveis e métodos de todas as classes superiores a ela no caminho.
28
Figura 5 – Diagrama UML representando herança de classes.
Um benefício importante da herança em orientação a objeto é a reusabilidade, visto
que os métodos em uma classe não precisam ser redefinidos nas suas subclasses, a menos que
uma delas requeira uma implementação distinta.
Há duas possibilidades ao associar um objeto a uma classe:
•
os objetos de uma superclasse são todos os objetos dessa classe em conjunto
com todos os objetos de todas as suas subclasses;
•
os objetos de uma superclasse são todos os objetos dessa classe exceto os
objetos de suas subclasses.
A escolha mais utilizada nos sistemas desenvolvidos é a segunda possibilidade.
2.3.6 – Acoplamento tardio (late binding)
Um objeto pode conter um valor numérico para um determinado atributo, e o próximo
objeto da mesma classe pode conter um outro tipo de valor, por exemplo caractere, para o
29
mesmo atributo. Desta forma, tipos de dados de um atributo não são conhecidos até o
momento da execução, podendo, duas diferentes instâncias de uma mesma classe conter
valores de diferentes tipos para o mesmo atributo. Esta característica é designada de
acoplamento tardio [Rob e Coronel, 1995].
Figura 6 Relação de
inventário
com tipo
de dado pré-determinado.
Figura 7 - Classe inventário com acoplamento prévio.
Figura 8 - Classe inventário com acoplamento tardio.
2.3.7 – Completeza Computacional
30
A completeza computacional está associada à capacidade de executar qualquer tipo de
operação em uma determinada linguagem de programação.
Nesse sentido, a maioria das linguagens de consulta do modelo relacional são
deficientes, pois não são capazes de formular todos os tipos de procedimentos desejados, em
razão de não possuírem controle de fluxo, entre outras características.
Essa característica pode ser alcançada nas linguagens de programação, devido a sua
estrutura permitir a expressão de qualquer tipo de procedimento. Do ponto de vista de um
Banco de Dados essa característica é uma novidade, tendo em vista que, por exemplo, a SQL
(padrão de linguagem de consulta no modelo relacional) não é computacionalmente completa
[Nassu e Setzer, 1999] [Rob e Coronel, 1995].
2.3.8. – Extensibilidade
Todo sistema de banco de dados possui tipos de dados pré-definidos, tais como:
strings, float, double, real etc.
Extensibilidade é a habilidade de definir novos tipos de dados, o que, geralmente, não
é possível em um modelo relacional, mas sim no modelo orientado a objeto. Do ponto de vista
do usuário, não deve haver distinção no gerenciamento entre os tipos definidos por ele e tipos
definidos pelo sistema [Atkinson, 1989].
31
2.3.9 – Persistência de Objetos
A persistência é uma característica intrínseca de um banco de dados, garantindo que o
tempo de vida de um dado perdure mais que o tempo de vida da aplicação, para o mesmo
poder ser utilizado posteriormente. Em um SGBD relacional, o dado é representado por
relações, que são salvas e recuperadas através de uma linguagem de consulta (SQL). Em um
SGBDOO os dados são representados por objetos, e podem ser consultados também por uma
linguagem de consulta, como por exemplo, Object Query Language (OQL). Porém, a
identificação dos objetos que devem ou não ser persistidos, pode ser realizada através das
seguintes técnicas [Silberschatz, 1999]:
•
Persistência por classe – todas as instâncias criadas a partir de uma classe
tornam-se persistentes, se a mesma for declarada como persistente;
•
Persistência por criação – o objeto é determinado como transiente ou
persistente na sua criação;
•
Persistência por marcação – em qualquer momento do tempo de vida de um
objeto pode-se marcá-lo como persistente;
•
Persistência por referência – designa-se um ou mais objetos como raízes de
persistência. Todos os objetos que são referenciados a partir dele tornam-se
persistentes automaticamente.
32
2.3.10 – Capacidade de gerenciamento de armazenamento secundário
Trata-se da capacidade de utilizar recursos (índices, otimização de consultas entre
outros) para o gerenciamento de grandes volumes de dados. Essa coordenação pelo SGBD
ocorre de forma transparente para o usuário [Rob e Coronel, 1995].
2.3.11 – Capacidade de prover concorrência
Os SGBDOOs devem dar o mesmo nível de suporte dos SGBDs convencionais no que
se refere ao gerenciamento de usuários que acessam concorrentemente o banco de dados (vide
item 2.2.3 – Controle de Concorrência).
2.3.12 – Recuperação
Segue o mesmo princípio dos sistemas convencionais, devendo o SGBDOO assegurar a
recuperação em caso de falhas de software ou hardware (vide item 2.2.4 – Recuperação).
2.3.13 – Consulta simples de dados (queries “ad hoc”)
Nesse caso, deve haver uma linguagem de consulta ao banco de dados de forma
simplificada que satisfaça os seguintes critérios:
•
ser uma linguagem de consulta de alto nível: significa que a linguagem deve
ser capaz de expressar consultas mais complexas de forma compacta,
utilizando-se de pouco código;
•
ser eficiente: trata-se da capacidade da linguagem formular consultas
utilizando um otimizador;
33
•
ser uma aplicação independente: trata-se da possibilidade de ser utilizada por
quaisquer bancos de dados.
2.4 – PERSISTÊNCIA
A persistência de um dado é definida pelo período de tempo em que ele existe e pode
ser utilizado [Atkinson, 1983]. Pode ser descrita pelas categorias demonstradas na tabela 3, a
seguir:
Categoria
1
2
3
4
5
6
7
8
Descrição
Resultados transientes de uma expressão
Variáveis locais
Variáveis globais
Dados que duram todo o tempo de execução de um programa
Dados que duram por várias execuções de vários programas
Dados que duram tanto quanto a utilização dos programas que a utilizam
Dados que duram por várias versões de um mesmo programa
Dados que duram por várias versões do sistema de persistência
Tabela 3 – Tempos de duração dos valores de dados.
As categorias de 1 a 4 são definidas como dados transientes ou de período curto e são
utilizadas pelas linguagens de programação em geral. As categorias de 4 a 8 são definidas
como dados persistentes ou de período longo e são utilizadas por sistemas de arquivos ou
sistemas de bancos de dados [Atkinson e Morrison, 1995]. Esta distinção surgiu por causa do
tamanho e do custo relativo dos dispositivos de armazenamento de dados.
Os sistemas de banco de dados têm como objetivo garantir a persistência dos dados,
devendo trabalhar com um meio físico de armazenamento não-volátil. Porém, esse tipo de
armazenamento é relativamente lento, e os sistemas de banco de dados têm que ser projetados
e estruturados para compensar e minimizar esta característica, a fim de que a mesma não
influencie no fornecimento de seus serviços.
34
As linguagens de programação têm como objetivo o processamento dos dados,
associando-se com um meio físico de armazenamento rápido. Porém, esse tipo de
armazenamento é volátil, e as linguagens de programação não conseguem persistir suas
informações mais do que a duração da execução de um programa [Brown, 1988].
Quando uma linguagem de programação quer utilizar dados persistentes, ou seja,
necessita transformar seus dados transientes em persistentes para reutilizá-los posteriormente,
é preciso recorrer a um banco de dados ou utilizar um meio físico não-volátil de
armazenamento. Nesse caso, a persistência está relacionada exclusivamente com um meio
físico de armazenamento não-volátil. Finalmente, pode-se entender a persistência de um dado
como a transformação de um estado transiente para um estado persistente.
2.4.1 – Persistência Ortogonal
A persistência ortogonal é definida através de três princípios:
•
Ortogonalidade de tipo – todos os dados podem ser persistentes independente
de seu tipo;
•
Independência de persistência – um dado é tratado da mesma forma
independente de ser transiente ou persistente;
•
Identificação de persistência – o mecanismo de identificação de objetos
persistentes não é relacionado com o seu tipo.
Se nenhum desses três princípios é atendido, a persistência não é ortogonal [Atkinson
e Morrison, 1995].
35
O último princípio é conhecido também como persistência transitiva (termo utilizado
pela ODMG – Object Data Management Group) ou também como persistência por referência.
A persistência por referência não é somente uma representação desse princípio, mas também
sua principal implementação, já que este é o único método de persistência que além de
independer do tipo do dado, não causa problemas de referências inválidas ao persistir um objeto
e deixar os outros objetos dependentes dele em um estado transiente.
A ortogonalidade surge da comparação entre o sentido de utilização do dado e o
sentido de persistência do mesmo. Dois sentidos podem ser chamados ortogonais quando
entre eles se forma um ângulo reto, ou seja, apesar de se encontrarem em um ponto, eles
nunca são contrários, nem opostos. Quando se fala de persistência ortogonal, pode-se dizer
que o sentido de utilização do dado é ortogonal ao sentido de persistência do mesmo, porque
um não interfere no outro, apesar de atuarem sobre um mesmo ponto, o dado. Em termos
gerais pode-se dizer que a persistência é ortogonal quando a mesma é independente da
utilização do dado, que é a forma mais desejada de persistência [Atkinson e Morrison, 1995].
2.5 – LINGUAGENS DE PROGRAMAÇÃO PERSISTENTES
A fim de se fornecer persistência dos dados em uma aplicação sem a utilização de um
SGBD, pode-se estender uma linguagem de programação para suportar tal persistência. Desta
maneira, a linguagem torna-se persistente [Silberschatz, 1999].
Uma linguagem de programação persistente é uma linguagem de programação
estendida com estruturas para tratar dados persistentes. A principal filosofia que há por trás
dessas linguagens de programação é tornar a persistência ortogonal ao tipo de objeto. Em
outras palavras, qualquer tipo de objeto pode ser persistido [Khoshafian, 1994].
36
Algumas linguagens que suportam a persistência ortogonal são chamadas de linguagens de
programação ortogonalmente persistentes, mas pode-se dizer que toda a linguagem que oferece
suporte à persistência dentro da própria linguagem é uma linguagem de programação persistente.
Porém, esse suporte pode ocorrer em diferentes graus de ortogonalidade e transparência,
dependendo de quais princípios da persistência ortogonal são atendidos.
É muito difícil atender todos os princípios de persistência ortogonal. Todas as tentativas de
implementação tiveram que modificar levemente a própria linguagem ou modificar o ambiente de
execução da mesma. Por isso, ao adicionar a persistência ortogonal a uma linguagem, uma nova
linguagem é criada. Foi assim com as linguagens S-Algol e Java que ao adicionarem a
persistência ortogonal tornaram-se PS-Algol e PJava, respectivamente [Danielsen, 1998].
A maioria das tentativas de se adicionar persistência ortogonal a uma linguagem foi feita
com linguagens que suportavam os paradigmas da orientação a objeto. Porém, não
necessariamente uma linguagem de programação tem que ser orientada a objeto para ser
persistente. Existem outros sistemas que adicionam o suporte à persistência em uma linguagem de
programação sem modificar a mesma ou seu ambiente de execução. Isso pode ser feito através de
bibliotecas de código geradas na própria linguagem. Tal suporte não cria uma nova linguagem,
nem a torna persistente, mas adiciona o suporte de persistência a mesma.
2.6 – INCOMPATIBILIDADE DE IMPEDÂNCIAS (IMPEDANCE MISMATCH)
O banco de dados relacional e suas extensões têm sido largamente utilizados na indústria
por muitos anos como um padrão para o armazenamento de dados [Ambler, 2003]. Por outro
lado, tem crescido a adoção das linguagens orientadas a objeto, assim como as outras tecnologias
e ferramentas que envolvem a orientação a objetos na construção de sistemas.
37
A tecnologia relacional suporta o armazenamento de dados em relações e a
manipulação destes dados através da linguagem de consulta SQL. A tecnologia orientada a
objeto representa um dado como um objeto, e traz diversos paradigmas para se construir
aplicações efetuando essa representação.
Um sistema tem a necessidade de garantir persistência a seus dados, assim como
utilizar uma linguagem que construa a aplicação propriamente dita fornecendo o acesso dos
dados ao usuário. Supondo um banco de dados relacional e uma linguagem orientada a objeto,
ambos devem trabalhar em conjunto na construção de um sistema. Nessa união, entretanto,
encontramos o problema da incompatibilidade de impedâncias.
Impedância é uma expressão utilizada em engenharia elétrica e compreende a resistência
que um conjunto apresenta a uma determinada carga aplicada sobre ele. A fim de se utilizar o
máximo de potência de vários conjuntos que se interligam fazendo parte de um sistema maior, as
impedâncias entre eles devem estar casadas, ou seja, serem equivalentes [Irwin, 2000].
Na área de software podemos dizer que os conjuntos em si são as camadas de uma
aplicação, devendo se integrar para que o dado transite do usuário até o banco de dados e vice-versa.
As impedâncias dessas camadas (a de aplicação orientada a objeto e a de persistência relacional) são
incompatíveis porque a representação dos dados entre elas é diferente. Então, nessa área, a
incompatibilidade de impedâncias refere-se à inerente diferença que existe entre os modelos de
dados relacionais e os orientados a objeto, representando um dado de maneiras diferentes.
As implicações resultantes desse problema podem abranger desde o aprendizado de
duas linguagens e tecnologias diferentes para se construir um mesmo sistema, até a
construção de uma camada de conversão de tipos de dados. Tudo isso para o sistema trabalhar
com essas duas tecnologias. Conclui-se, portanto, que para utilizar essas duas tecnologias e
resolver o problema de impedância sempre haverá um custo.
38
3 – SISTEMAS PREVALENTES
Persistir dados (nesse caso o estado de objetos) sempre foi um problema quando se trata de
software orientado a objeto. Com o passar dos anos, tentou-se armazenar objetos de diferentes
maneiras, incluindo bancos de dados relacionais, arquivos eXtensible Markup Language (XML) e
arquivos texto. Essas abordagens geram sobrecarga no desenvolvimento de software, direcionando
esforços para transformar objetos em alguma outra representação de dados para que seu estado
possa ser persistido. Essa transformação destrói completamente o conceito de encapsulamento da
orientação a objetos, além de não manter o software puramente orientado a objeto [Villela, 2002].
Estima-se que 30% do código gerado em uma aplicação que utiliza um banco de dados
como camada de persistência está relacionado à movimentação e organização desses dados e não
na modelagem e solução do problema real para o qual o sistema foi proposto [Brown, 1988]. Uma
solução para este problema é a prevalência de objetos ou sistemas prevalentes.
3.1 – BREVE HISTÓRICO
A prevalência de objetos é um conceito desenvolvido por Klaus Wuestefeld
[Wuestefeld, 2001] e colaboradores. Sua primeira implementação, conhecida como Prevayler,
tornou-se disponível em novembro de 2001 como um software de código aberto. Atualmente,
existem diversas implementações deste conceito em evolução contínua [Villela, 2002].
3.2 – DEFINIÇÕES DE PREVALÊNCIA
Prevalência é um modelo de persistência transparente de objetos em memória. Em um
sistema prevalente (que utiliza o modelo de prevalência para persistência de objetos), todos os
objetos são mantidos na memória principal do computador. Uma classe específica é utilizada
39
para garantir que todas as alterações efetuadas nesses objetos não sejam perdidas. Consultas são
executadas recuperando objetos em memória, tornando seu acesso mais rápido do que através
de consultas executadas diretamente em disco [Villela, 2002].
Pode-se analisar o modelo de prevalência comparando-o aos três princípios da persistência
ortogonal: independência de persistência, ortogonalidade e identificação de persistência.
Entende-se como princípio da independência de persistência, uma escala de
transparência que define o grau de diferença no tratamento entre um dado persistente e um
dado transiente [Moss e Hosking, 1996]. Um extremo inferior nesta escala pode ser
encontrado em aplicações que utilizam um banco de dados relacional como camada de
persistência de dados. Nesse caso, a diferença no tratamento desses dados é de tal ordem que,
diferentes linguagens têm que ser utilizadas para tratar cada conjunto de dados. Para dados
persistentes é utilizada uma linguagem que o banco de dados relacional compreende, como
por exemplo SQL, e no caso dos dados transientes a linguagem da própria aplicação.
Em um outro extremo, podem-se citar aplicações construídas com linguagens de
programação persistentes, que tratam dados transientes e persistentes da mesma maneira. Essa
transparência completa é difícil de ser alcançada, pois novas linguagens têm que ser criadas para
atender este princípio integralmente. Um nível satisfatório de transparência pode ser encontrado
diminuindo-se a diferença no tratamento desses dados até o ponto onde ainda exista um controle
em relação à intenção de se trabalhar com dados persistentes ou com dados transientes.
Na prevalência, a diferença no tratamento dos dados ocorre na manipulação dos
objetos, onde para se inserir ou alterar um objeto persistente deve-se utilizar uma classe
específica. Essa técnica de diferenciar o tratamento através de uma classe indica um bom
nível de transparência, pois implica diretamente na modelagem da solução e não na
40
codificação. Dessa forma, não existe diferença no tratamento de um dado persistente para um
dado transiente no nível de implementação do sistema.
O princípio da ortogonalidade trata da independência entre a persistência e o tipo do
dado. A ortogonalidade completa também é difícil de ser realizada e pode não ser necessária
em alguns casos [Moss e Hosking, 1996]. Algumas estruturas de dados têm sua natureza
transiente, e não faz sentido nenhum torná-las persistentes para uma posterior recuperação. É
o caso de objetos que são ligados ao contexto de execução de uma aplicação, que somente
fazem sentido dentro dela. Objetos que representam canais de acesso a disco, acesso a rede,
gerenciamento de memória para a execução do programa, entre outros, só fazem sentido
dentro da execução de um programa. Persistir tais objetos pode trazer sérios problemas de
implementação [Kienzle e Romanovsky, 2000].
Por outro lado, um alto grau de independência, ou seja, liberdade para poder persistir
qualquer classe do domínio do projeto, é muito útil principalmente na modelagem da solução,
pois assegura que o modelo de objetos possa ser completo e independente da persistência do
dado que está sendo modelado [Atkinson e Morrison, 1995].
Na prevalência, duas restrições são feitas em relação aos tipos de dados que podem ser
persistidos ou não: as classes devem ser serializáveis e determinísticas [Oliveira, 2003].
A serialização é a transformação da estrutura do objeto em memória para uma
seqüência de bytes, podendo a mesma ser armazenada e depois restaurada ao estado anterior
do objeto. No caso da prevalência, ela é o processo que salva o estado do objeto, e deve ser
suportada pela linguagem que implementará a prevalência.
Os objetos também devem ser determinísticos, ou seja, devem sempre chegar ao
mesmo estado quando exposto ao mesmo conjunto de comandos.
41
Essas duas restrições não implicam diretamente em um baixo nível de ortogonalidade,
já que dentre as classes de negócio que modelam o problema, e que realmente devem ser
persistidas, as duas características podem ser atendidas.
O último princípio, o da identificação de persistência, é totalmente atendido pela
prevalência, uma vez que tal princípio implementa a persistência por referência. Este tipo de
identificação de persistência é realizado incluindo-se no modelo de objetos uma classe que
representa a raiz da árvore de persistência. Todos os objetos pertencentes a essa árvore, ou
seja, que são referenciados direta ou indiretamente por este objeto, são considerados
persistentes. Esse tipo de solução é um pouco intrusiva na modelagem do problema, pois
devem ser criadas classes que não representam nenhuma entidade do domínio do problema,
mas apenas para proverem a persistência.
A prevalência é um modelo de persistência e pode ser implementada em qualquer
linguagem orientada a objeto que suporte a serialização de objetos.
3.3 – ESQUEMA GERAL DE FUNCIONAMENTO DA PREVALÊNCIA
Como o armazenamento principal dos objetos é feito em um meio físico volátil
(memória principal do computador), surge a questão de como a prevalência garante a
persistência dos objetos após várias execuções do sistema.
Utilizando os mecanismos de log de transação e de backup, a prevalência garante que,
mesmo se o sistema for desligado ou parar de executar, nenhum objeto armazenado em
memória será perdido. Isso acontece porque os dois mecanismos salvam o estado de um ou
mais objetos em um meio físico não-volátil (disco), podendo restaurar o seu valor caso
alguma falha ocorra.
42
O log de transação é implementado pela utilização de classes que representam as
alterações em objetos, serializando e salvando-as em um meio físico não-volátil.
A forma de backup utilizada é o “snapshot”, responsável por salvar o estado de todos
os objetos da memória principal para o disco, tirando uma espécie de “fotografia” do estado
dos objetos naquele dado momento.
A persistência do estado dos objetos só é possível devido ao mecanismo de
serialização, que deve ser suportado pela linguagem na qual foi implementada a prevalência.
Figura 9 - Serialização do estado de um objeto.
A serialização consiste no processo de transformação da estrutura de um objeto em
memória para um formato sequencial, o qual pode ser armazenado ou transportado através de
uma rede. A sequência de bytes resultante deste processo (figura 9 – dados serializados) pode
ser chamada de estado serializado do objeto, pois contém o estado do objeto (valor dos
atributos), além de todas as informações necessárias para a reversão do processo. Reconstruir o
objeto em memória a partir de seu estado serializado é chamado de desserialização [Strawmyer,
2003]. O objeto não pode ser acessado quando está em seu estado serializado, pois sua estrutura
não é mais reconhecida como um objeto, e sim como uma seqüência de bytes.
43
Apesar de terem a mesma função (salvar o estado do objeto em disco), esses
mecanismos são complementares devido as suas características e, devem ser utilizados em
conjunto para que a persistência seja garantida,pois o “snapshot” pode se tornar lento, caso o
modelo de objetos ocupe muito espaço em memória, e utilizá-lo cada vez que o modelo fosse
alterado, poderia ter grande impacto no desempenho do sistema.
O log de transação, por sua vez, é utilizado toda vez que uma alteração em um objeto
persistente é efetuada, gravando a alteração em um arquivo. Com o decorrer das alterações
nos objetos do sistema, o arquivo onde é armazenado o log tende a ficar muito maior do que o
arquivo onde é armazenado o snapshot, pois várias alterações podem ser feitas em um mesmo
objeto sem alterar seu tamanho original.
Utilizar o mecanismo de log de transação sem um estado inicial (“snapshot”) pode
impactar no desempenho do sistema, pois o tempo de carga e reexecução destas alterações
tende a ser muito maior que a carga do arquivo de “snapshot”. Isto se agrava e passa a ser
perceptível após um tempo maior de utilização do sistema [Oliveira, 2003].
O log de transação é gravado pelo próprio sistema de prevalência, já o “snapshot”
deve ser invocado pela aplicação, em períodos de pouca utilização da mesma.
No caso da restauração de uma falha ou reinício da aplicação, o sistema de prevalência
procura pelo último “snapshot” gravado, restaurando o estado do sistema para o momento em
que a gravação foi feita. A seguir, são reexecutados todos os logs das alterações que foram
efetuadas no sistema, posteriores ao “snapshot” tirado, para que o sistema volte ao estado
anterior à falha ou ao desligamento do sistema.
Embora esses mecanismos utilizem o disco rígido, o armazenamento principal do modelo
de prevalência ainda é a memória principal do computador, pois os objetos residem e são
44
manipulados nela. O formato de gravação do objeto em disco é resultante da serialização de seu
estado, não podendo ser acessado ou alterado enquanto estiver nesse formato.
Enquanto em um SGBD o esquema de recuperação está relacionado à ocorrência de
falhas, na prevalência, o log de transação e o “snapshot” funcionam tanto no caso de falhas,
quanto no caso de reinício do sistema.
Figura 10 - Diagrama temporal do início de execução de um sistema prevalente.
45
Analisando a linha do tempo da figura 10 da esquerda para a direita, é mostrado como
acontece o esquema de recuperação. A prevalência procura pelo último “snapshot” gravado
em disco e o desserializa, montando os objetos em memória. Em seguida, são localizados e
desserializados todos os logs posteriores a esse “snapshot”. Com a reexecução desses logs o
sistema volta ao estado consistente anterior a falha.
Em um sistema prevalente a persistência começa a ser inserida na modelagem do
sistema. Todos os objetos de negócio (objetos que representam entidades diretamente
relacionadas ao problema a ser modelado) devem ser referenciados por um objeto raiz (que
pode não ser um objeto de negócio) para que a persistência seja garantida.
O objeto raiz pode representar o banco de dados do sistema, pois contém a referência a
todos os objetos que devem ser persistidos na aplicação.
A persistência dos objetos de negócio é garantida através da ligação entre o objeto raiz e
o sistema de prevalência, realizada antes de qualquer acesso aos objetos. No caso de um SGBD,
essa ligação pode ser representada como a conexão do cliente ao banco de dados.
Na modelagem, métodos são criados para implementar regras do sistema, alterando e
persistindo o estado dos objetos de negócio. Em uma aplicação orientada a objeto que utiliza
um SGBD relacional como camada de persistência, os métodos que persistem os estados dos
objetos devem ser implementados invocando comandos SQL (update, insert, delete). Por
outro lado, no sistema de prevalência esses métodos têm que ser substituídos por classes que
representam alterações nos objetos. Essas classes são serializadas e gravadas em disco antes
de serem executadas, assegurando a persistência das alterações e implementando o log de
transação. Tais classes recebem o nome de command ou transaction em algumas
implementações da prevalência.
46
O funcionamento de um sistema prevalente pode ser resumido pelos seguintes passos:
•
Uma vez iniciado o sistema, todos os objetos são criados ou carregados em
memória, disponibilizando o sistema para uso;
•
Todas as consultas são feitas procurando os objetos em memória;
•
Todas as alterações efetuadas nos objetos são representadas por classes
serializáveis (transaction ou command);
•
Cada objeto transaction ou command submetido ao sistema, antes de ser
executado é escrito em um arquivo de log;
•
Quando o sistema é reiniciado, todas as alterações previamente gravadas em
arquivos de log são reexecutadas de forma a restaurar seu estado original;
•
Periodicamente, fotos (“snapshots”) do estado completo dos objetos em
memória são gravados em disco.
Analisando a linha do tempo da figura 11 da esquerda para a direita, é mostrado como
são realizados os mecanismos de log de transação e “snapshot”. A classe command (que
representa a alteração de objetos) é serializada e gravada em um arquivo de log antes de cada
execução. Em um momento posterior, um “snapshot” é gravado em disco, contendo o estado
de todos os objetos em memória.
47
Figura 11 - Diagrama temporal de um sistema prevalente em funcionamento.
Algumas regras devem ser seguidas para se criar um sistema prevalente que funcione
conforme a descrição anterior:
•
Todos os objetos que forem persistidos devem ser serializáveis;
•
Todas as alterações no modelo de objetos devem ser representadas por classes
também serializáveis;
•
O sistema deve ser determinístico, ou seja, o sistema deve sempre chegar ao
mesmo estado quando exposto ao mesmo conjunto de comandos [Oliveira, 2003].
48
3.4 – IMPLEMENTAÇÕES: PREVAYLER E BAMBOO.PREVALENCE
A prevalência é um modelo de persistência. Para se construir um sistema prevalente, ou
seja, que utiliza a prevalência como camada de persistência, precisa-se de uma implementação
concreta para a linguagem a ser utilizada. A pouca documentação existente sobre este modelo,
surgiu a partir da primeira implementação para a linguagem Java: o Prevayler [Wuestefeld, 2001].
Essa implementação está atualmente na versão 2.0, e além de implementar todos os
requisitos da prevalência também tem características interessantes, como o suporte a rollback.
Todas as classes que fazem as alterações nos objetos persistentes implementam uma interface
chamada de transaction. Se acontecer algum erro nessas classes (gerados por uma exceção),
os comandos de alteração dos objetos são desfeitos. Isso ocorre porque esse mecanismo
utiliza uma cópia do modelo de objeto em memória, executando primeiro as alterações nesse
modelo, e posteriormente, se nenhum erro ocorrer, aplica as alterações no modelo principal de
objetos na memória. Tal mecanismo utiliza o dobro de memória ocupado pelo modelo de
objetos [Wuestefeld e Roubieu, 2003].
A
versão
C#.NET
(plataforma
de
desenvolvimento
Microsoft),
chamada
de
Bamboo.Prevalence, foi implementada seguindo o modelo de prevalência do Prevayler e atualmente
se encontra na versão 1.4. Dentre as suas principais características podem-se citar a alteração
transparente de objetos em memória e um “kit” para a migração da estrutura de objetos (alteração de
classes) com o sistema já em produção.
A primeira característica possibilita a alteração dos objetos persistentes em memória
diretamente através da chamada de seus métodos, sem a necessidade de fazê-la através de
uma classe. O próprio sistema de prevalência se encarrega de interceptar a chamada desse
método e fazer a gravação do log da alteração em disco. A alteração de objetos através de
classes específicas ainda é possibilitada nessa implementação.
49
A segunda característica surgiu da necessidade de manutenção de um sistema
prevalente em produção. A questão se relaciona à alteração de sua estrutura, caso necessite
realizar alguma manutenção no sistema, pois os objetos estão sempre em memória.
Em um sistema que utiliza um banco de dados relacional como camada de
persistência, a alteração da estrutura dos dados é feita diretamente no banco de dados,
adicionando-se ou removendo-se uma coluna de uma tabela conforme a alteração. Com a
nova estrutura de banco de dados, altera-se o programa para refletir as alterações no sistema, e
ao se instalar o novo banco de dados e a respectiva versão da aplicação, a manutenção do
sistema é realizada.
Em um sistema prevalente não existe essa distinção do dado transiente da aplicação e
do dado persistente no banco de dados. A estrutura do objeto no código é a mesma do objeto
persistente em memória. Diante disso, o Bamboo.Prevalence resolve esse problema através de
um “kit de migração” que possibilita a alteração e conversão de estruturas de objetos
existentes em memória.
Um arquivo XML representa a alteração na estrutura de uma ou mais classes do
sistema. Um exemplo da adição de dois novos atributos (X e Y) nos objetos da classe A,
localizados no arquivo sistema.dll, pode ser demonstrado através da figura 12.
Figura 12 – Arquivo XML que representa a alteração da estrutura de um objeto.
50
O sistema em produção é desligado e um “snapshot” é gravado em disco para que a
conversão seja aplicada. A ferramenta de migração intercepta a desserialização desse
“snapshot”, aplicando a conversão na estrutura das classes especificadas no arquivo XML.
Abaixo são listadas algumas implementações da prevalência de objetos:
Implementação
Bamboo.Prevalence
Common Lisp Prevalence
Madeleine
Py Per Syst
VTN Prevayler
Linguagem
.NET (C#)
Common Lisp
Ruby
Python
Objective-C
Endereço na Internet
http://bbooprevalence.sourceforge.net/
http://homepage.mac.com/svc/prevalence/readme.html
http://madeleine.sourceforge.net/
http://sourceforge.net/projects/pypersyst
http://sourceforge.net/projects/vtnprevayler
Tabela 4 – Implementações da prevalência em diversas linguagens.
As implementações, mostradas na tabela acima, adicionam características à
prevalência de acordo com suas próprias necessidades. Não existe um documento formal
sobre o que é o modelo de prevalência e quais características devem ser utilizadas a fim de
que uma biblioteca de código possa dizer quando adiciona o suporte à persistência na
linguagem através da prevalência. Suas versões são atualizadas por seus autores e não têm
nenhum correspondente entre si ou com o modelo de prevalência.
Todas essas implementações do modelo de prevalência citadas na tabela 4 são
softwares de código aberto e podem ser encontradas nos respectivos endereços na internet.
51
3.5 – VANTAGENS E DESVANTAGENS DA PREVALÊNCIA
Um dos objetivos da prevalência é tornar o desenvolvimento de software orientado a
objeto que necessita de persistência mais simples e mais produtivo. Pode-se comparar a
prevalência a outros sistemas que provêem o serviço de persistência para a construção de
aplicativos.
3.5.1 – Eliminação da tecnologia relacional
A eliminação da incompatibilidade de impedâncias torna-se a principal vantagem
quando se faz a comparação entre o sistema de prevalência e o SGBD relacional. Problemas
decorrentes dessa incompatibilidade também são eliminados, tais como:
•
Linguagens diferentes para manipular dados transientes e dados
persistentes – utilizando-se de um banco de dados relacional é necessário
embutir a linguagem SQL na linguagem da aplicação a fim de se manipular
dados persistentes [Atkinson, 1989]. Além de causar ilegibilidade no código,
não é possível saber se a sintaxe da linguagem SQL está correta em tempo de
compilação, gerando erros que só podem ser percebidos com a aplicação em
funcionamento;
•
Conversão de tipos de dados – os bancos de dados relacionais trabalham com
uma representação de tipos de dados diferente da utilizada em uma linguagem
orientada a objeto. Para a linguagem de programação garantir a persistência de
seus objetos no banco de dados, uma conversão deve ser aplicada. Nesse item,
não cabe somente a conversão de tipos primitivos, como números inteiros e
decimais, mas também a conversão de objetos em relações. Na transformação
de tipos primitivos somente o nome do dado tem que ser alterado. Entretanto,
52
na conversão de objetos em relações, o encapsulamento do objeto tem que ser
violado a fim de que seus dados possam ser inseridos em comandos SQL para
gravação;
•
Camada de mapeamento objeto-relacional – por causa das diferenças
citadas acima, é necessário implementar código específico para fazer a
comunicação entre as duas tecnologias (relacional e orientada a objeto),
direcionando esforços na construção de uma camada de persistência dos dados
e não na modelagem e solução do problema real para o qual o sistema foi
proposto;
•
Maior aprendizado de tecnologia – a utilização de duas tecnologias
diferentes para a construção de um mesmo sistema aumenta o tempo de
aprendizado da equipe de desenvolvimento, implicando diretamente no
aumento do tempo de construção do sistema [Ambler, 2003];
•
Dificuldade de realização de testes automatizados do código – bancos de
dados relacionais impõem dificuldades na realização de testes automatizados
de um sistema. Não somente na sincronização do código com a estrutura do
banco de dados, mas principalmente na dependência de um banco de dados
estável e com dados suficientes para se realizar os testes. Isso pode implicar na
desistência da elaboração de testes automatizados, resultando na queda de
qualidade do sistema [Oliveira, 2003].
A maioria desses problemas podem ser resolvidos com a utilização de um banco de
dados orientado a objeto, removendo parcial ou integralmente a incompatibilidade de
impedâncias entre a tecnologia relacional e a orientada a objeto.
53
A prevalência ainda é considerada uma tecnologia emergente se comparada aos
SGBDs relacionais, existentes há muitos anos no mercado. Os sistemas prevalentes ainda são
pouco utilizados no mercado, não provando efetivamente sua maturidade como camada de
persistência de dados. A sua pouca idade reflete diretamente no pequeno número de
desenvolvedores que conhecem essa tecnologia.
3.5.2 – Ambiente unificado
Um SGBD (relacional ou orientado a objeto) é um sistema isolado e independente da
aplicação para a qual fornece o serviço de persistência de dados, podendo manter diversos
bancos de dados para diversos sistemas em um mesmo SGBD. Essa característica ainda pode
gerar os seguintes problemas:
•
Ambientes diferentes – a aplicação e o SGBD são ambientes separados,
requerendo manutenção e administração próprias de cada um;
•
Conectividade – a separação dos ambientes também gera problemas de
conectividade entre os dois sistemas. As aplicações têm que conhecer
bibliotecas específicas ou componentes genéricos para acessarem o banco de
dados, assim como a instalação de drivers correspondentes aos SGBDs
utilizados.
Em contrapartida, a remoção do SGBD implica na perda de características muito
importantes ao desenvolvimento e à manutenção de um sistema. O programa de interface de
acesso e o de armazenamento dos dados devem ficar separados, permitindo que cada cliente
utilizando uma interface possa interagir com os dados armazenados. Em um sistema que faz
uso de um SGBD para persistir seus dados, a separação é inerente, garantindo a administração
e manutenção do armazenamento dos dados de forma transparente. Porém, na prevalência, o
54
processo que armazena os dados deve ser criado pelo próprio desenvolvedor, implicando na
elaboração de software adicional para efetivar a manutenção e administração desse processo,
assim como o controle do acesso a ele. Outras características como a autorização e a consulta
“ad hoc” também são perdidas, obrigando o seu desenvolvimento, se necessário, na própria
aplicação.
3.5.3 – Representação única da solução
No desenvolvimento de um sistema orientado a objeto que utiliza um banco de dados
como camada de persistência, dois modelos têm que ser construídos e mantidos para
representar a solução do problema: o modelo de objetos e o modelo do banco de dados.
Qualquer alteração no projeto tem que ser refletida e sincronizada nestes dois modelos. A
figura a seguir mostra como fica este mapeamento:
Figura 13 - Três mapeamentos com duas representações da solução.
55
Supondo um sistema de administração acadêmica que não tenha suporte a controle de
mensalidades em uma primeira versão e que, posteriormente o usuário decida adicionar esse
serviço. Essa alteração na especificação do sistema (mundo real) obriga conseqüentemente a
alterações no programa (implementação de novos programas) e no banco de dados (relações
para armazenas as mensalidades). Nesse modelo, o banco de dados, os programas e o
problema proposto estão muito acoplados, e qualquer alteração em um deles, como por
exemplo, a divisão de uma relação em outras duas por questão de performance, implica
diretamente em uma alteração nos outros modelos.
Em um sistema prevalente a solução é modelada e mantida em um único modelo de
dados, o da própria aplicação, conforme demonstrado na figura a seguir:
Figura 14 - Um único mapeamento representando a solução.
A eliminação de todos os problemas mencionados conduz a uma redução significativa
no tempo de desenvolvimento de um sistema, demonstrando mais uma vantagem no uso da
prevalência.
56
3.5.4 – Armazenamento em memória
O desempenho do sistema em consultas é melhor do que nos SGBDs devido ao fato do
armazenamento ocorrer na memória principal do computador, sendo muito mais rápida do que
o acesso a disco.
Atualmente, pode se considerar a limitação de tamanho da memória principal uma
desvantagem nos sistemas prevalentes, já que esses a utilizam como armazenamento primário
de seus objetos. A cada dia tal limitação está diminuindo, mas a defasagem ainda é grande em
relação ao armazenamento em disco utilizado pelos SGBDs.
3.6 – APLICAÇÕES POTENCIAIS DE SISTEMAS PREVALENTES
Pode-se indicar a prevalência como camada de persistência para os sistemas que
tenham os seguintes requisitos:
•
Pequeno espaço de armazenamento de dados – como a prevalência
armazena os objetos na memória principal do computador, esse é o limite de
armazenamento do sistema. Aplicações que necessitam de uma rápida
expansão no espaço de armazenamento dos objetos para limites além da
memória principal, não são indicados para utilizarem a prevalência;
•
Alta performance de consulta – devido ao fato dos objetos residirem na
memória principal do computador, a consulta aos objetos é muito mais rápida
na prevalência, caracterizando os sistemas que tem esse como seu principal
requisito, os mais indicados a utilizarem a prevalência;
57
•
Possuir gerenciamento do processo de armazenamento dos objetos – para
sistemas que precisam separar os processos de programa e de armazenamento de
objetos para conseguir o acesso multiusuário, só é recomendada a prevalência se
existir um sistema externo que garanta o gerenciamento do processo de
armazenamento dos objetos. Caso contrário, essa tarefa terá que ser implementada
pela própria equipe de desenvolvimento. Nos sistemas em que os objetos e a
aplicação permanecem no mesmo processo, mas o acesso multiusuário é garantido
por um sistema externo, a prevalência também é indicada.
Um tipo de aplicação que se enquadra nos requisitos acima são websites que tenham um
grau de dinamicidade muito alto em seu conteúdo. Esse tipo de aplicação requer um alto nível de
consulta ao banco de dados, pois para cada acesso às páginas do website, no mínimo um acesso
ao banco de dados deve ser feito para montar a página a ser exibida. Websites com conteúdo
dinâmico não requerem muito espaço de armazenamento de dados, pois além de possuírem
poucas entidades de negócio, somente é armazenado o conteúdo dinâmico e não as páginas
inteiras do site. Um servidor web cuida do gerenciamento do processo e do provimento de acesso
multiusuário dos dados, suprimindo essa tarefa da equipe de desenvolvimento.
Uma outra característica da prevalência é o aumento de produtividade no
desenvolvimento de aplicações, que dependendo do tipo de aplicação requerida, essa
vantagem pode abranger um número maior de tipos de aplicações.
Quando as limitações de memória principal não forem mais um problema e a
prevalência estiver mais madura, uma gama muito maior de tipos de aplicações poderá ser
alcançada. Sistemas que atingirão seu limite de armazenamento em alguns anos, já utilizam a
prevalência, apostando que o armazenamento em memória RAM não será mais um problema
quando esse limite for alcançado.
58
4 – IMPLEMENTAÇÃO
4.1 – PRÉ-REQUISITOS
Para construir um sistema prevalente em Microsoft® .NET os seguintes softwares são
requeridos:
•
Microsoft® .NET Framework Software Development Kit (SDK) 1.1 – inclui
todas as ferramentas necessárias para o desenvolvimento de aplicações em
Microsoft® .NET. Pode ser conseguido gratuitamente no endereço:
http://www.microsoft.com/downloads/details.aspx?FamilyId=9B3A2CA63647-4070-9F41-A333C6B9181D&displaylang=en.
Também
é
possível
utilizar a versão 1.0, mas no exemplo de implementação utilizado nesse estudo
será utilizada a versão 1.1.
•
Bamboo.Prevalence
Microsoft®
.NET
1.3
que
–
implementação
pode
ser
da
conseguida
prevalência
no
em
endereço:
http://sourceforge.net/project/showfiles.php?group_id=61693&release_id=10
9035. Pode ser utilizada uma versão mais atualizada, mas neste exemplo de
implementação será utilizada a versão 1.3.
O Microsoft® .NET Framework Software Development Kit (SDK) 1.1 contém o
compilador C# que será utilizado para gerar o sistema prevalente em .NET. A implementação
da prevalência em .NET foi desenvolvida em C# mas pode ser implementada em qualquer
outra linguagem suportada pela plataforma Microsoft® .NET, como por exemplo Microsoft®
VB.NET ou Microsoft® JScript.NET.
59
Um sistema prevalente é uma aplicação em .NET que fornece suporte a persistência de
modo transparente. Como qualquer sistema orientado a objeto o primeiro passo a ser seguido
para o seu desevolvimento é a realização de sua modelagem.
Atualmente a plataforma de desenvolvimento Microsoft® .NET executa somente em
sistemas operacionais Windows (98 ou superior). Existe uma iniciativa de se portar essa
plataforma de desenvolvimento para o ambiente operacional UNIX, habilitando assim a
prevalência em Microsoft® .NET em outros sistemas operacionais. Isso, entretanto, não está
hoje disponível.
4.2 – DESENHO DA APLICAÇÃO
Aqui desenvolvemos um sistema de controle acadêmico com as seguintes
funcionalidades:
•
Manutenção de alunos – permite a inclusão, alteração e exclusão de um aluno
e busca pelo seu nome;
•
Manutenção de cursos – permite a inclusão, alteração e exclusão de um
curso;
•
Manutenção de etapas – permite a inclusão, alteração e exclusão de uma
etapa;
•
Efetivação de matrícula por etapa e curso – permite matricular um aluno em
um curso/etapa, criando um código de matrícula para o mesmo.
60
O modelo do sistema é representado pelo diagrama da figura 15.
Figura 15 - Modelo de objetos.
A classe Aluno contém um código para a criação da matrícula, além dos atributos
Nome e Endereco (um outro objeto). Esse código é utilizado na efetivação da matrícula,
fazendo a ligação entre o Aluno, o Curso e a Etapa através do objeto Matricula.
Todas as classes, com exceção de Endereco, possuem um atributo chamado Id que é a
identificação do objeto. Esse atributo é artificial, ou seja, não está relacionado com o domínio
do problema, e foi criado para obter uma referência aos objetos persistentes em execuções
posteriores do sistema. Como o tempo de vida dos objetos é maior que o da aplicação, deve-se
utilizar um identificador de objetos que também seja persistente, para o mesmo poder ser
referenciado fora do modelo de objetos, como por exemplo, na interface com o usuário. A
classe Endereco não possui um identificador de objetos persistente, pois somente é acessada
através da classe Aluno, que já apresenta um identificador de objetos persitente.
Esses identificadores de objeto são únicos para cada objeto criado no sistema,
diferenciando um objeto de outro da mesma classe. Pode-se fazer uma analogia com a chave
61
primária do modelo relacional, que também identifica unicamente uma entidade dentro de
uma relação no banco de dados.
O valor do identificador de objetos deve ser controlado pelo sistema para que
nenhuma repetição aconteça. Também se pode utilizar um tipo de dado que, ao ser criado, não
gere nenhum valor repetido, o que violaria a regra de identificação do objeto. Para as classes
Etapa e Curso, o atributo identificador do objeto é do tipo integer (valores entre –
2.147.483.648 e 2.147.483.647). Esse tipo de dado não garante a unicidade de seu valor,
havendo a necessidade da criação de um mecanismo de controle que não permita a repetição
do identificador para objetos diferentes. No caso das classes Etapa e Curso, o controle da
criação desses valores foi centralizada na classe SystemDatabase, que cria identificadores
únicos de objetos ao torná-los persistentes.
Diferentemente de uma modelagem relacional, pode-se utilizar além dos tipos
convencionais já existentes no sistema (long, integer etc.), classes criadas externamente.
Na classe Aluno, o identificador de objetos utilizado é de um tipo específico
pertencente à plataforma Microsoft® .NET, o GUID. Essa classe cria um valor único cada
vez que é instanciada, não necessitando de um controle externo que evite a repetição do
identificador de objetos para a classe Aluno.
4.3 – AMBIENTE WEB
Implementamos uma aplicação web. A figura 16 traz esquematicamente como ela está
organizada. As páginas web forneceram a interface ao cliente, que pode acessá-las e interagir
com a aplicação. Os web browsers fazem as requisições ao servidor, que executa um
programa correspondente (acessando os objetos) e devolve uma resposta ao usuário. O
62
servidor web é responsável por gerenciar tanto o acesso multiusuário quanto a manutenção do
processo onde residem os programas e os objetos do sistema, motivo pelo qual escolheu-se
esse modelo. Caso contrário, seria necessária a construção de código adicional para prover a
comunicação entre diversos clientes e o sistema prevalente. Como o objetivo deste estudo é a
utilização da prevalência para adicionar persistência a um sistema orientado a objetos, e não
aplicações web, é suficiente o detalhamento aqui apresentado.
Figura 16 - Ambiente de uma aplicação web.
4.4 – ADICIONANDO A PREVALENCIA AO MODELO
O modelo atende todas os requisitos propostos, mas se o sistema for executado os
objetos serão perdidos quando a execução for interrompida (o modelo não inclui bases de
dados), ou seja, os objetos ainda não persistem.
63
O primeiro passo para adicionar a prevalência é criar uma classe que irá referenciar
todos os objetos que devem persistir no sistema (objeto raíz da persistência). Pode-se fazer
uma analogia desta classe a um banco de dados, pois todos os objetos persistentes são
referenciados e encontrados a partir dela. Uma instância dessa classe deve ser conectada à
biblioteca da prevalência quando o sistema for iniciado.
Figura 17 - Modelo de objetos com suporte à prevalência.
No modelo da figura 17, uma instância da classe SystemDatabase (que será criada
pela biblioteca de prevalência) é o objeto raíz da persistência que contém vetores que
referenciam os objetos persistentes. Pode-se utilizar vetores ou qualquer outro tipo de
estrutura de dados para referenciar os objetos persistentes, inclusive a referência direta aos
objetos persistentes. Como no sistema um dos requisitos é armazenar mais de um objeto
persistente da mesma classe, uma estrutura do tipo vetor será utilizada para referenciar essas
instâncias, pois novas referências podem ser adicionadas.
64
A classe SystemDatabase se utiliza de uma classe ArrayList do próprio framework
.NET, representando um vetor de objetos com crescimento dinâmico. Além disso, fornece
algumas funções utéis, como por exemplo, a busca binária dentro deste vetor.
Analogamente pode-se comparar esses vetores a relações de um banco de dados
relacional, pois armazenam dados de um mesmo tipo.
4.5 – IMPLEMENTANDO A PREVALÊNCIA
Após implementar as classes de negócio, deve-se garantir que todas essas classes
sejam serializáveis, a fim de que os mecanismos de snapshot e log de transação possam ser
aplicados e, se algum erro ocorrer, os objetos possam ser recuperados. Na plataforma de
desenvolvimento Microsoft® .NET , a serialização é feita automaticamente desde que a classe
contenha o atributo [Serializable], conforme o exemplo a seguir:
[Serializable]
public class Aluno
{
private String _name;
private Matricula _matricula;
private Endereco _address = null;
private System.Guid _id;
public Aluno()
{
_id = System.Guid.NewGuid();
_address = new Address();
}
}
Exemplo 1 – Serialização automática com o uso do atributo [Serializable].
Em uma aplicação web Microsoft® .NET a função Application_Start, como mostra o
próximo código, é executada antes da aplicação estar disponível para os usuários a fim de fazer a
conexão entre a biblioteca de prevalência e o objeto raiz de persistência.
65
protected void Application_Start(Object sender, EventArgs e)
{
1 PrevalenceEngine engine = PrevalenceActivator.CreateTransparentEngine
(typeof(SystemDatabase), @"c:\data");
2 SystemDatabase sysdb = engine.PrevalentSystem as SystemDatabase;
3 this.Context.Application.Add("SystemDatabase", sysdb);
4 this.Context.Application.Add("PrevalenceEngine", engine);
}
Exemplo 2 – A função Application_Start faz a conexão entre a biblioteca de prevalência e o objeto.
Na linha 1 (como destacado abaixo) é criado o objeto que representa o mecanismo da
prevalência (engine). Este objeto possui as principais funções da prevalência, como a
execução de classes de comandos (command) e de snapshots.
PrevalenceEngine engine = PrevalenceActivator.CreateTransparentEngine
(typeof(SystemDatabase), @"c:\data");
Exemplo 3 – Criação do objeto engine.
Na criação desse objeto é passado como parâmetro o tipo da classe que representa o
objeto raiz da persistência (SystemDatabase) e o caminho onde serão gravados os “snapshots”
e os logs de transação.
Na linha 2 o objeto engine cria o objeto raiz da persistência que é referenciado pela
variável SysDB. Nesse momento é verificado se existe algum “snapshot” e/ou logs de
transação gravados em disco (c:\data). Caso exista, a recuperação dos dados é efetuada.
SystemDatabase sysdb = engine.PrevalentSystem as SystemDatabase;
Exemplo 4 – Criação do objeto raiz da persistência.
As duas últimas linhas (3 e 4) adicionam esses objetos ao contexto da aplicação,
tornando-os disponíveis a todas as páginas e classes da aplicação, para que as mesmas possam
66
utilizar-se das funções destes objetos, como por exemplo, executar uma classe de comando
(serviço do objeto engine) ou acessar um objeto persistente (serviço ao sysdb).
this.Context.Application.Add("SystemDatabase", sysdb);
this.Context.Application.Add("PrevalenceEngine", engine);
Exemplo 5 – Adicionando objetos ao contexto da aplicação.
A memória do sistema em execução pode ser ilustrada através da figura 18.
Figura 18 - Objetos persistentes e transientes.
67
Nessa figura todos os objetos persistentes são referenciados pelo objeto raiz da
persistência. Os objetos que não são apontados por ele são transientes, ou seja, serão
destruídos quando a execução da aplicação terminar. Quando um objeto é criado ele
primeiramente é transiente pois é referenciado por uma variável (identificador de objeto) que
também é transiente. Para torná-lo persistente, basta adicionar uma referência a ele no objeto
raiz da persistência. A troca do estado do objeto (de transiente para persistente) deve ser feita
através de uma classe de comando (command), assim como alterações em objetos
persistentes, para que as mesmas não sejam perdidas se o sistema parar de executar.
4.6 – MANIPULANDO OBJETOS PERSISTENTES
Utilizando a biblioteca de prevalência Bamboo.Prevalence, pode-se exemplificar uma
classe de comando através do código abaixo:
[Serializable]
public class Command : ICommand
{
.
.
.
}
Exemplo 6 – Exemplo de uma classe de comando.
A classe deve implementar a interface ICommand porque é através dela que a
biblioteca de prevalência consegue invocar um método específico para a execução do
comando (Execute). Antes da execução do comando, um log é gravado em disco, que é a
serialização da própria classe de comando. Quando o sistema reinicia, essa classe é
desserializada e executada novamente para que a alteração não seja perdida. Todas as
operações (inclusão, alteração, exclusão) que alteram o estado de qualquer objeto persistente,
inclusive do objeto raiz da persistência, devem ser feitas por classes de comando.
68
Operações que não alteram o estado de nenhum objeto persistente (consultas), devem
ser feitas por classes de consulta (não são serializadas), que implementam a interface IQuery:
public class Query : IQuery
{
.
.
.
}
Exemplo 7 – Exemplo de uma classe de consulta.
4.6.1 – Inclusão
No caso de uma inclusão, a classe de comando deve alterar o objeto raiz de
persistência, adicionando uma referência para o novo objeto. No exemplo 8, a seguir,
demonstra-se a classe de comando que inclui um objeto da classe Curso:
[Serializable]
public class AdicionaCursoComando : ICommand
{
Curso _curso = null;
public AdicionaCursoComando (Curso curso)
{
_curso = curso;
}
public object Execute(object system)
{
((SystemDatabase)system).AdicionaCurso(_curso);
((SystemDatabase)system).ListaCurso.Sort();
return null;
}
}
Exemplo 8 – Exemplo de uma classe de inclusão.
O código que traduz o objetivo do comando está dentro do método Execute. Na classe
do exemplo 8, esse método transforma um objeto transiente em persistente, chamando um
método da classe SystemDatabase que cria um identificador para o novo objeto e depois o
insere no vetor correspondente.
69
Como essa classe tem que ser serializada, o atributo [Serializable] deve constar antes
do nome da classe. O código cliente que invoca este comando para tornar um objeto do tipo
Curso persistente pode ser visualizado no exemplo 9:
1 Curso curso = new Curso(txtNome.Text);
2 AdicionaCursoComando comando = new AdicionaCursoComando(curso);
3 ExecuteCommand(comando);
Exemplo 9 – Código que invoca o comando que torna o objeto do tipo Curso persistente.
Na linha 1 do exemplo 9, cria-se um objeto do tipo Curso a partir de um controle que
contém o nome do curso digitado pelo usuário na tela do sistema. Por enquanto esse objeto é
transiente e seu identificador é a variável curso.
1 Curso curso = new Curso(txtNome.Text);
A segunda linha cria uma instância da classe AdicionaCursoComando passando o
objeto curso como parâmetro.
2 AdicionaCursoComando comando = new AdicionaCursoComando
(curso);
A última linha invoca o método ExecuteCommand do objeto engine para executar o
comando. Antes de ser executado o objeto é serializado em disco.
O diagrama de sequência da figura 19 mostra como a inclusão de um novo curso
ocorre:
70
Figura 19 - Diagrama de sequência da inclusão de um objeto persistente.
Essas classes de alteração (comando) devem ser utilizadas também para que um
mecanismo de bloqueio (lock) seja realizado no sistema. Todas as classes de alteração que
implementam ICommand são executadas unicamente no sistema, ou seja, nenhum outro
comando é executado até que o corrente termine, garantindo a consistência do modelo de
objetos em memória.
Pode-se dizer que a execução dos comandos é serializada, ou seja, somente é
executado um comando por vez no sistema. Esse mecanismo é importante para atualizações,
mas é prejudicial para a performance do sistema se for utilizado para consultas, já que uma
consulta não altera o estado de nenhum objeto no sistema. Desse modo, várias consultas
podem ser realizadas em paralelo sem que o modelo de objetos fique em um estado
inconsistente. [Oliveira, 2003].
71
4.6.2 – Consulta
As classes que funcionam como consultas no sistema, devem implementar a interface
IQuery. Essas classes não são serializadas justamente porque não alteram o estado de nenhum
objeto persistente. Para cada consulta a ser realizada em um ou mais classes persistentes,
deve-se criar uma classe de consulta correspondente.
Não se deve acessar um objeto diretamente para consulta, pois a classe de consulta
implementa um mecanismo de bloqueio de leitura, isto é, a biblioteca de prevalência verifica
se não existe nenhuma outra classe de alteração (comando) sendo executada. Caso exista, a
consulta não pode ser realizada enquanto o comando não terminar, pois a classe de consulta
pode visualizar um estado inconsistente do modelo de objetos. Deste modo, a biblioteca de
prevalência garante que várias classes de consulta possam ser executadas paralelamente caso
nenhum comando estiver em execução.
Em síntese, uma classe de alteração bloqueia a execução de todas os outras classes,
independentes se elas são de consulta ou de alteração, mas uma classe de consulta não
bloqueia a execução de outras classes de consulta [Oliveira, 2003].
72
No exemplo 10, a seguir, é mostrado um exemplo de uma classe de consulta:
[Serializable]
public class AchaCursoConsulta : IQuery
{
long _id;
public AchaCursoConsulta (long Id)
{
_id = Id;
}
public object Execute(object system)
{
return ((SystemDatabase)system).AchaCurso(_id);
}
}
Exemplo 10 – Código que cria uma classe de consulta.
O comando de consulta, mostrado no código anterior, busca pelo identificador de
objeto no vetor respectivo dentro do objeto raiz de persistência (método FindCourse da classe
SystemDatabase faz uma busca binária dentro do vetor CourseContainer). A seguir retorna
uma cópia do objeto para o cliente que executa este comando, a fim de que o objeto seja
exibido na tela, por exemplo. Um código cliente que invoca essa classe de consulta pode ser
demonstrado no código de exemplo 11, abaixo:
1 AchaCursoConsulta consulta = new AchaCursoConsulta (Id);
2 Curso curso = ExecuteQuery(consulta);
Exemplo 11 – Código que invoca uma classe de consulta.
A primeira linha cria um novo objeto do tipo AchaCursoConsulta (que é uma classe
de consulta) passando o identificador do objeto a ser localizado (Id).
1 AchaCursoConsulta consulta = new AchaCursoConsulta(Id);
A segunda linha executa o comando de consulta e retorna o objeto encontrado.
73
2 Curso curso = ExecuteQuery(consulta);
Se não for encontrado nenhum objeto com o identificador passado, é retornado o valor
null para o objeto curso. Dessa maneira, esse código pode exibir uma mensagem para o
usuário de objeto não encontrado. O diagrama de seqüencia a seguir ilustra a execução dessa
classe de consulta no sistema:
Figura 20 - Diagrama de sequência da consulta de um objeto persistente
Através do diagrama, pode-se perceber que não existe serialização da classe de
consulta AchaCursoConsulta.
4.6.3 – Alteração
Para a alteração de um objeto persistente, o mesmo deve ser localizado antes de ser
alterado. O código a seguir, exemplo 12, representa uma classe que faz a alteração em um
objeto do tipo Curso persistente:
74
[Serializable]
public class AtualizaCursoComando : ICommand
{
Curso _curso;
public AtualizaCursoComando (Curso curso)
{
_curso = curso;
}
public object Execute(object system)
{
Curso cursoPersistido =
((SystemDatabase)system).AchaCurso(_curso);
cursoPersistido.Nome = _curso.Nome;
return null;
}
}
Exemplo 12 – Código da classe de alteração do objeto Curso.
Dentro do método Execute, temos a chamada do método AchaCurso do objeto raiz de
persistência, para encontrar um objeto que tenha o mesmo identificador do objeto passado
como parâmetro (_curso). Esse objeto transiente deve ter o identificador preenchido assim
como todos os valores dos atributos que foram alterados. Como a classe Curso tem somente a
propriedade nome além do identificador, somente é necessário fazer uma cópia do valor do
atributo nome do objeto transiente alterado para o persistente. O código cliente que invocaria
esta alteração está descrito a seguir, exemplo 13:
1
2
3
4
Curso curso = new Curso(Id);
RecebeDadosdaTela(curso);
AtualizaCursoComando comando = new AtualizaCursoComando(curso);
ExecuteCommand(comando);
Exemplo 13 – Código de alteração da classe Curso.
Esse código é uma atualização em um objeto curso já existente, ou seja, antes deste
código ser executado o objeto a ser alterado foi localizado e exibido na tela do sistema.
Quando o usuário alterou os dados e clicou no botão salvar, este código é invocado.
75
A primeira linha cria um objeto do tipo Curso com um identificador de objeto válido,
ou seja, o identificador do objeto persistente que foi exibido anteriormente na tela, com a
variável curso apontando para ele.
1 Curso curso = new Curso(Id);
A segunda linha tem um método (RecebeDadosdaTela) que atualiza o objeto curso
com todos os valores dos atributos que foram alterados na tela do sistema.
2 RecebeDadosdaTela(curso);
As duas últimas linhas criam uma instância da classe (AtualizaCursoComando) de
comando que faz a alteração de um objeto do tipo Curso, e invoca o método
ExecuteCommand passando esta instância.
3 AtualizaCursoComando comando = new AtualizaCursoComando(curso);
4 ExecuteCommand(comando);
O diagrama de seqüência a seguir, ilustra como é a execução da alteração de um objeto
curso persistente:
76
Figura 21 - Diagrama de sequência de alteração de um objeto persistente.
4.6.4 – Exclusão
A exclusão de um objeto no sistema é feita através da execução de uma classe de
comando que remove a referência do objeto raiz de persistência para o objeto a ser excluído.
Nesse exemplo de implementação, o objeto a ser excluído é armazenado em um vetor de
objetos e a exclusão é efetuada, tornando o objeto transiente. A classe de comando
(RemoveCourseCommand) que remove um objeto do tipo Course do sistema é mostrada no
exemplo 14, a seguir:
[Serializable]
public class ExcluiCursoComando : ICommand
{
long _id;
public ExcluiCursoComando(long id)
{
_id = id;
}
77
public object Execute(object system)
{
((SystemDatabase)system).ListaCurso.Remove(_id);
return null;
}
}
Exemplo 14 – Código da classe de comando que remove o objeto do tipo Curso.
O código cliente que chama este comando é mostrado no exemplo 15, a seguir:
1 ExcluiCursoComando comando = new ExcluiCursoComando (Id);
2 ExecuteCommand(comando);
Exemplo 15 – Código cliente que chama o comando que remove o objeto do tipo Curso.
A primeira linha cria um comando que remove um objeto do tipo Curso do sistema,
passando o identificador do objeto a ser removido (Id).
1 ExcluiCursoComando comando = new ExcluiCursoComando (Id);
A segunda linha executa o comando.
2 ExecuteCommand(comando);
O diagrama a seguir ilustra essa execução:
78
Figura 22 - Diagrama de sequência de exclusão de um objeto persistente.
As operações realizadas nas outras classes do sistema são muito semelhantes às
operações apresentadas nesta seção, razão pela qual não foram demonstradas neste trabalho.
4.7 – DESEMPENHO
Com base no exemplo de implementação, foram desenvolvidos testes que avaliaram o
tamanho do processo que armazena os objetos e do “snapshot” gravado em disco, assim como
o desempenho da busca de objetos em um sistema prevalente. Os testes abrangeram as
seguintes tarefas:
•
Inclusão de n objetos;
79
•
Ordenação do vetor de objetos;
•
“Snapshot” dos objetos;
•
Busca pelo primeiro objeto do vetor;
•
Busca pelo último objeto do vetor.
Para fins de avaliação de desempenho, o log de transação foi desabilitado, pois o seu
uso implicaria no aumento do tempo de inserção, dificultando a realização dos testes.
Os testes foram executados 3 vezes para os valores de n igual a 10.000, 100.000 e
1.000.000 de objetos. A tabela 5 apresenta os resultados obtidos.
n = 10.000 objetos
Tarefa
Teste 1
7.430.144
Tamanho do processo em memória (bytes)
31,25
Busca do primeiro objeto do vetor (ms)
15,625
Busca do último objeto do vetor (ms)
3,796875
Tempo total de execução (s)
1.232
Tamanho do snapshot em disco (Kbytes)
n = 100.000 objetos
Tarefa
Teste 1
24.047.616
Tamanho do processo em memória (bytes)
46,875
Busca do primeiro objeto do vetor (ms)
31,25
Busca do último objeto do vetor (ms)
24,265625
Tempo total de execução (s)
12.306
Tamanho do snapshot em disco (Kbytes)
n = 1.000.000 objetos
Tarefa
Teste 1
178.274.304
Tamanho do processo em memória (bytes)
31,25
Busca do primeiro objeto do vetor (ms)
31,25
Busca do último objeto do vetor (ms)
297,828125
Tempo total de execução (s)
123.048
Tamanho do snapshot em disco (Kbytes)
Teste 2
7.430.144
15,625
15,625
3,875
1.232
Teste 3
7.430.144
31,25
31,25
3,828125
1.232
Teste 2
24.047.616
46,875
15,625
24,15625
12.306
Teste 3
24.047.616
15,625
31,25
22,953125
12.306
Teste 2
177.967.104
46,875
31,25
296,625
123.048
Teste 3
178.274.304
31,25
31,25
297,765625
123.048
Tabela 5 - Resultados dos testes de desempenho.
A tabela 5 mostra que tanto o espaço utilizado em memória para armazenar os objetos
(tamanho do processo) quanto o espaço utilizado em disco para armazenar o estado serializado
dos objetos (tamanho do “snapshot” em disco), cresceram proporcionalmente em relação ao
80
número de objetos inseridos. Como somente o estado dos objetos (e mais algumas informações
a respeito das classes) é armazenado em disco, o tamanho do espaço utilizado em memória é
maior que o espaço utilizado em disco. A grande variação encontrada nos tempos de busca dos
objetos, mesmo entre os testes executados com o mesmo número de objetos, indica que esses
valores não podem ser considerados absolutamente como indicadores de performance para a
busca de objetos em memória. Devido ao valor muito baixo do tempo de busca (alguns
milisegundos), diversas interferências (ou até mesmo a falta de precisão na medição) podem ter
causado uma variação tão grande (em alguns casos essa diferença chega a 100%).
Esses indicadores podem ser analisados relativamente, comparando-se os tempos de
busca de objetos realizado em domínios diferentes. A tabela 5 mostra que o tempo de busca
de um objeto entre 10.000 é praticamente o mesmo de uma busca efetuada em um domínio de
1.000.000 de objetos. Isso demonstra que o desempenho de busca não é degradado pelo
aumento no número de objetos, provando não ser proporcional ao crescimento do sistema.
81
5 – CONCLUSÃO
Comparada com outras tecnologias de persistência, a prevalência tem características
que a aproximam mais de uma linguagem de programação persistente (LPP) do que de um
SGBD. Em uma escala de transparência, a persistência fornecida pela prevalência só não se
iguala às LPPs, que conseguem atingir o nível máximo. As LPPs, entretanto, tem um alto
custo de implementação, pela modificação da linguagem ou de seu ambiente de execução, o
que não ocorre no caso da prevalência.
A prevalência tem uma portabilidade melhor para linguagens orientadas a objeto do
que as LPPs, pois deve-se apenas reescrever a bilblioteca na linguagem destino, ao invés de se
criar uma nova linguagem. A portabilidade da prevalência não é difícil de ser realizada, pois
seu código não é extenso.
No desenvolvimento de sistemas orientados a objeto, a utilização da prevalência como
camada de persistência é mais produtiva que o SGBDR, pois elimina a incompatibilidade de
impedâncias. A prevalência, porém, é limitada a orientação a objeto, diferentemente dos
SGBDRs que podem atender tanto as linguagens procedurais quanto as orientadas a objeto.
Os SGBDOOs também eliminam a incompatibilidade de impedâncias, mas não
promovem uma integração completa da aplicação com o repositório de objetos como no
ambiente unificado da prevalência.
Observa-se também que a utilização da prevalência permite reduzir os custos no
desenvolvimento de sistemas orientados a objeto, eliminando licenças de uso, hardware e
equipe de profissionais especializados na administração e gerenciamento de SGBDs. Esta
redução, porém, implica na perda de suporte do fabricante, já que a prevalência é um software
livre de código aberto.
82
O conceito que mais se assemelha na prevalência a uma transação dos SGBDRs é o de
classes de comando, pois podem agrupar diversas operações em uma única tarefa. Quanto à
propriedade de atomicidade, a prevalência somente apresenta esta característica mediante a
utilização de um mecanismo de rollback, disponível apenas em algumas de suas
implementações e não utilizada neste trabalho.
A consistência das transações são garantidas no sistema através da serialização da
execução de classes de comando, não permitindo execuções paralelas. Desse modo, o sistema
garante que nenhuma classe de comando irá visualizar o estado do sistema enquanto outra
estiver sendo executada, pois o sistema pode estar em um estado inconsistente. A propriedade
de isolamento é uma consequência direta desta serialização.
Quanto à propriedade de durabilidade, a prevalência garante a persistência de objetos
no sistema.
Uma linguagem orientada a objeto que implementa a prevalência não necessita de um
SGBD para persistir seus objetos, embora existam outros serviços necessários ao
desenvolvimento de sistemas, como o gerenciamento do acesso multiusuário e do
armazenamento dos dados, que são fornecidos por um SGBD. Dessa forma, um sistema
prevalente que necessite desses serviços deve implementá-los ou confiar seu fornecimento a
outro software, como por exemplo, um servidor de aplicacões ou um servidor web.
De acordo com o exemplo de implementação, a utilização da prevalência demostrouse bastante produtiva, reduzindo o tempo de desenvolvimento do sistema. Se fosse utilizado
um banco de dados relacional, haveria a necessidade de se elaborar um segundo modelo para
representar os dados, enquanto que na prevalência a única visão existente dos dados é o
próprio código. Além disso, a utilização de um SGBDR requer a construção de código
83
adicional para solucionar o problema de representação dos dados, existente entre as
tecnologias orientada a objeto e relacional.
O fato da prevalência utilizar somente uma tecnologia, a orientada a objeto, assim
como o SGBDOO, habilita o desenvolvedor a trabalhar em um ambiente totalmente orientado
a objeto, evitando um mapeamento implícito no desenvolvimento, que ocorre quando é
utilizado um SGBDR. Esta característica permite novas possibilidades de implementação de
soluções, antes inviáveis com o uso de um SGBDR. Para ilustrar uma possibilidade, no
exemplo de implementação foi possível atribuir um tipo novo para o atributo chave de uma
classe do sistema, que na realidade era outra classe criada no próprio sistema. Isso não limita
a escolha de tipos de atributos das classes somente aos tipos existentes no sistema.
Em um sistema prevalente, o acesso direto aos objetos sem a utilização de classes de
comando, ou de classes de consulta, é muito facilitado, pois tanto objetos transientes quanto
persistentes estão disponíveis da mesma forma. Isso pode induzir a um erro na utilização do
sistema, pois o acesso direto não serializa as alterações efetuadas, podendo ser perdidas se o
sistema parar de executar antes de um “snapshot”. Cabe ao desenvolvedor atentar para esse fato.
A simplicidade de se adicionar a prevalência no sistema foi comprovada pela adição
apenas de uma classe ao modelo de objetos e pela fácil conexão desta classe com a biblioteca
de prevalência. Na codificação essa simplicidade ficou menos evidente, pois foi necessária a
criação de classes de comando para efetuar alterações em objetos persistentes.
Os resultados obtidos pelos testes comprovaram o alto desempenho na consulta de
objetos fornecida pela utilização da prevalência. O esforço de busca demonstrou-se não ser
proporcional ao número de objetos existentes no sistema, já que a busca de um objeto em uma
lista de 10.000 apresentou um desempenho semelhante a uma busca realizada em uma lista de
1.000.000 de objetos.
84
Por se tratar de uma tecnologia emergente, várias questões relacionadas ao
desenvolvimento de sistemas precisam ainda ser investigadas e avaliadas. Entretanto, já existem
algumas aplicações que utilizam, com sucesso, essa tecnologia. Essas aplicações se caracterizam
principalmente por atenderem os requisitos de baixo volume de armazenamento, alto desempenho
de consulta e baixo tempo de desenvolvimento do sistema. Dentre esses casos, podemos citar o
website da emissora de televisão Rede Record (www.rederecord.com.br) que utiliza a prevalência
para armazenar todo o conteúdo dinâmico do website, incluindo notícias, descrição de programas,
realização de enquetes, grade de programação etc.
A evolução da tecnologia de armazenamento de memória volátil pode minimizar uma
das principais limitações da prevalência, possibilitando assim a sua maior utilização no
desenvolvimento de sistemas orientados a objeto.
85
6 – REFERÊNCIAS BIBLIOGRÁFICAS
AMBLER, S. Agile Database Techniques: Effective Strategies for the Agile Software
Developer. Nova Iorque: John Wiley & Sons, 2003.
ATKINSON, M. P. et al., An Approach to Persistent Programming. Computer Journal, v.
26, n. 4, 1983. Disponível em: <http://www.dcs.stand.ac.uk/research/publications/download/ABC+83a.pdf>. Acesso em: 20 out. 2003.
ATKINSON, M. P. et al., The Object-Oriented Database System Manifesto. In Proc. of the
1st Int. Conf. on Deductive and Object-Oriented Databases, Kyoto, Japão, 1989.
Disponível em: <http://citeseer.ist.psu.edu/atkinson89objectoriented.html>. Acesso em:
01 nov. 2003.
ATKINSON, M.P. e MORRISON, R. Orthogonally Persistent Object Systems.
VLDBJournal, Pacific Grove, v. 4, n. 3, 1995. Disponível em: <
http://citeseer.nj.nec.com/atkinson95orthogonally.html >. Acesso em: 10 nov. 2003.
BROWN, A. L. Persistent Object Stores. Tese (Ph.D thesis) - Computational Science,
University
of
St.
Andrews,
1988.
Disponível
em:
<
http://citeseer.nj.nec.com/brown88persistent.html >. Acesso em: 15 out. 2003.
DATE, C.J. Introdução a Sistemas de Banco de Dados. 8 ed., Rio de Janeiro: Campus,
1991.
DANIELSEN, A. The Evolution of Data Models and Approaches to Persistence in
Database Systems. University of Oslo, 1998. Disponível em:
<http://www.fing.edu.uy/inco/grupos/csi/esp/Cursos/cursos_act/2000/DAP_DisAvDB/doc
umentacion/OO/Evol_DataModels.html>. Acesso em: 23 out. 2003
ELMARSI, R. e NAVATHE, S. Fundamentals of Database Systems. 3 ed., Vancouver:
Addison-Wesley, 2000.
IRWIN, J. Análise de circuitos em engenharia. 4 ed., São Paulo: Makron Books, 2000.
KHOSHAFIAN, S. Banco de Dados Orientado a Objeto. Rio de Janeiro: Livraria e Editora
Infobook S.A.,1994.
KIENZLE, J. e ROMANOVSKY, A. A Framework based on Design Patterns for
Providing Persistence in Object-Oriented Programming Languages. Newcastle:
University of Newcastle, 2000. Disponível em:
<http://citeseer.nj.nec.com/kienzle00framework.html>. Acesso em: 12. nov. 2003.
MOSS, J. e HOSKING, A. Approaches to adding persistence to Java. In: First International
Workshop on Persistence and Java, Drymen, Escócia, 1996. Disponível em: <
http://citeseer.nj.nec.com/moss96approaches.html >. Acesso em: 23 out. 2003.
NASSU, E. e SETZER, V. Bancos de Dados Orientados a Objetos. São Paulo: Editora
Edgard Blücher Ltda, 1999.
86
OLIVEIRA, R. B. (Autor da camada de prevalência para CLI – ECMA 335). Comunicação
pessoal, 2003.
ROB, P. e CORONEL, C. Database Systems – Design, Implementation and Management.
2 ed., Danvers:International Thomson Publishing Company, 1995.
SILBERSCHATZ; A.; KORTH, H. e SUDARSHAN, S. Sistemas de Banco de Dados. 3 ed.,
São Paulo: Makron Books, 1999.
STRAWMYER, M. Serialization/Deserialization in .NET, 2003. Disponível em <
http://www.developer.com/net/csharp/article.php/3110371>. Acesso em: 20 nov. 2003.
VILLELA, C. An introduction to object prevalence, 2002. Disponível em: <http://www106.ibm.com/developerworks/web/library/wa-objprev/ 01/06/2003>. Acesso em: 17 out.
2003.
WUESTEFELD, K. Prevayler, 2001. Disponível em: <http://www.prevayler.org/wiki.jsp>.
Acesso em: 10 jul. 2003
WUESTEFELD, K. e ROUBIEU, J. Prevayler: Objetos Java Invulneráveis. Mundo Java,
Curitiba, n. 1, pp. 25-31, set.-out. 2003.
87
7 – BIBLIOGRAFIA COMPLEMENTAR
ARAÚJO, N. Jr. Banco de Dados: Passado, Presente e Futuro. Developers’ Magazine, Rio de
Janeiro, n. 47, p. 13, jul. 2000.
FILGUEIRAS, E. Híbridos: ORDBMS são viáveis para OODBMS ? Developers’ Magazine,
Rio de Janeiro, n. 47, pp. 16-17, jul.-2000.
GAMMA, E. Design Patterns: Elements of Reusable Object-Oriented Software .
Vancouver: Addison-Wesley Pub Co, 1995.
KIM, W. Modern Database Systems – the object model, interoperability and beyond.
New York: Alan Press, 1995.
KROENKE, D. M. Database Processing – Fundamentals, Design & Implementation. 9
ed., New Jersey: Prentice Hall, 2003
MENDONÇA, S. e SAPIENZA, S. SGBDOO: Uma realidade próxima ou um futuro distante?
Developers’ Magazine. Rio de Janeiro: n. 47, p. 21, julho-2000.
OLIVEIRA, R. B. Bamboo.Prevalence - a .NET object prevalence engine. Disponível em:
<http://bbooprevalence.sourceforge.net/10/08/2003>. Acesso em: 12 ago. 2003.
O’NEILL, P. e O’NEILL, E.. Database-Principles Programming Performance. 2 ed., San
Francisco: Morgan Kaufmann Publishers, 2001.
RICCARDI, G. Principles of Database Systems with Internet and Java Apllications.
Boston: Addison-Wesley, 2001.
STONEBRAKER, M. readings in... database systems., 3 ed., San Francisco: Morgan
Kaufmann Publishers, 1998.
ZANIOLO, C. et al. Advanced Database System. San Francisco: Morgan Kaufmann
Publisher Inc, 1997.
88
Download