Visual Basic 6  : DAO - Replicando sua base de dados


"Você trabalha como vendedor para uma grande empresa e está acabando de fechar uma negócio com um cliente . Após verificar a disponibilidade do produto em seu notebook você preenche o pedido faz uma conexão com o seu servidor e envia os dados da transação. Vale lembrar que neste momento o mesmo pode estar acontecendo com os 50 vendedores da sua Empresa que estão em campo.(Você esta a 800 Km de distância da sede da companhia e , por falar nisto , já faz uns três meses que você não coloca os pés no escritório.)..."

O pequeno exercício de ficção acima já faz parte integrante do nosso dia a dia. Uma das tecnologias que torna o fato possível  é a replicação das informações contidas banco de dados central da companhia. Replicação das informações ? Afinal o que é replicação ?

Replicação de Banco de dados

Podemos definir como replicação o processo de criação de cópias de um banco de dados e a sincronização das mudanças ocorridas nos dados entre todas as cópias. Explicando melhor: 

A lógica de replicação vai além de um simples backup do banco de dados , como se poderia supor a primeira vista, pois ao invés de duplicar todos os componentes do banco de dados é realizada a sincronização no conjunto de replicação ( os bancos de dados ) comparando-os registro a registro para assegurar que conterão os mesmos dados e então copiando as alterações do banco de dados Principal(mestre de construção) para qualquer um dos bancos de dados da réplica.  

No  caso do vendedor , ele carrega no seu notebook uma réplica do banco de dados . Quando faz a conexão com o servidor  o processo de sincronização entra em cena e os registros são comparados em sua réplica com os registros do Mestre de Construção ( o banco de dados principal ) . Se você adicionou ou fez qualquer alteração nos registros  eles serão copiados e as alterações refletidas no banco de dados Principal. Da mesma forma se qualquer dado novo ou alteração foi feita no banco de dados principal (lembre-se que temos 50 vendedores que podem atualizar a base de dados usando o mesmo processo) elas serão copiadas para sua réplica no mesmo momento.

A replicação pode também ser utilizada para otimizar até um simples Backup do Banco de dados. Assim,  em um rede com diversos usuários  fazer um backup do banco de dados  implica em não disponibilizar o acesso do banco de dados aos usuários durante o processo do backup por razões de integridade e segurança . Neste período de tempo a rede ficara inativa . A réplica resolve o problema pois irá permitir a cópia apenas dos registros alterados desde o último backup e com isso você não precisa copiar o banco de dados inteiro.

Para ambientes onde a atualização das informações precisam ser quase que instantâneas (sistema de seguranças) e onde o processo de atualização dos dados é intenso a replicação do banco de dados não é aconselhável.

Da Teoria a Prática - Fazendo um banco de dados Replicável

A primeira coisa a fazer para utilizar a replicação com um  banco de dados é tornar o  banco de dados que você deseja replicar em um Mestre de Construção ( Master Design). Vale dizer aqui que vamos utilizar o DAO - Data Access Object - para controlar a réplica.  Com isto em mente vamos dar abaixo os objetos DAO que contém propriedades e métodos  utilizados no processo de replicação:

Propriedade/Método Objeto Descrição
KeepLocal TableDef e QueryDef Determina se o objeto pode se tornar uma réplica
Replicable Database, TableDef e QueryDef Determina se o objeto é duplicado durante a sincronização.
MakeReplica Database Cria uma a partir do Meste de Construção
Synchronize Database Sincroniza um banco de dados de réplica com o Mestre de Construção
ReplicaFilter TableDef Permite fornecer uma cláusula WHERE SQL que rege quais registros da tabela serão duplicados
PartialReplica Relation Em uma réplica parcial permite determinar qual a relação rege a réplica dos registros.
ReplicableBool DataBase Equivalente a propriedade Replicable (Mais difícil definir )

Neste artigo vamos utilizar o banco de dados Mestre.mdb no diretório c:\teste . Então antes de tornar nosso banco de dados Replicável vamos dar uma olhada e analisar a sua estrutura:

Fig 1.0 - As tabelas do banco de dados Fig 2.0 - Todas as tabelas do sistema
Fig 3.0 - Os campos da tabela Clientes Fig 4.0 - As propriedades do banco de dados

Criando um Mestre de Construção ( Master Design)

A primeira coisa a fazer para usar a réplica com o código DAO  é fazer com que o banco de dados possa ser duplicado. Fazemos isto incluindo a propriedade dinâmica - Replicable - ao objeto Database . 

Isto deve ser feito nas seguintes  etapas:

  1. Fazer uma cópia do banco de dados 

  2. Abrir o banco de dados no modo exclusivo

  3. Anexar a propriedade á coleção Properties do objeto

  4. Definir o valor da propriedade Replicable como "T"

Vamos agora criar um mestre de construção do nosso banco de dados Mestre.mdb. 

Private Sub cmdreplicar_Click()

Dim dbMestre As Database
Dim Propriedade As Property
Const CaminhoCopia = "c:\teste\copia\CopiaMestre.mdb"

On Error GoTo trata_erro

'faz uma copia do banco de dados ( prevenir é bom né...)
FileCopy txtcaminho.Text, CaminhoCopia

' abre o banco de dados no modo exclusivo
Set dbMestre = OpenDatabase(txtcaminho.Text, True)

'cria e define a propriedade replicable
With dbMestre
     Set Propriedade = .CreateProperty("Replicable", dbText, "T")
    .Properties.Append Propriedade
    .Properties("Replicable") = "T"
End With


MsgBox " O banco de dados foi copiado para " &  dbMestre.Name & _
" e sua propriedade Replicable foi definida para : " &  dbMestre.Properties("Replicable").Value & _
" => Acabamos de criar um mestre de construção ", vbInformation, " Replicação "

dbMestre.Close
Exit Sub

trata_erro:
Select Case Err.Number
   Case 3367   ' a propriedade replicabel já existe
         Exit Sub
    Case Else
         MsgBox " Erro : " & Err.Description
End Select

End Sub

Veja bem você não criou um novo arquivo , apenas modificou o arquivo existente - Mestre.mdb . Esta operação somente pode ser realizada uma única vez. (veja o tratamento de erros onde prevemos tal situação...)

Quais as modificações ocorreram durante o processo ? Vamos mostrar isto a seguir...

1-) A alteração nos campos de cada tabela :

Abra o arquivo Mestre.mdb usando o Visdata e Expanda as propriedades para a tabela clientes. A seguir exiba as propriedades do objeto Fields e observe.Note que foram criados três novos campos para a tabela :

  1. s_Generation

  2. s_GUID

  3. s_Lineage

Figura 5.0 - Os novos campos inseridos durante o processo

Na verdade os três novos campos são inseridos em todas as tabelas do banco de dados. O que significam ?

2-)Alteração nas tabelas do sistema:

Vamos analisar as tabelas do sistema . Observe a figura abaixa com as novas tabelas inseridas após termos feito o banco de dados replicável:

 

 

Deu para perceber que muitas novas tabelas foram inseridas ( compare com figura 2.0).

O propósito destas tabelas é gerenciar a sincronização de forma a garantir que durante a replicação todos os membros do conjunto de replicação foram atualizados.

Por exemplo:

A tabela MSysReplicas contém informação sobre cada membro do conjunto de replicação. 

 

Figura 6.0 - As novas tabelas do sistema

 

 

 

 

 

 

 

 

 

 

 

2-)Alteração nas propriedades do banco de dados :

Vamos observar as novas propriedades do banco de dados comparando a figura abaixo com a figura 4.0 acima:

Perceba que novas propriedades foram inseridas.

Observe que agora existe a propriedade Replicable com o valor igual a T. Isto indica que a replica pode ser feita para este banco de dados.

Observe que a propriedade ReplicaID  foi incluída . Ela identifica o banco de dados de forma única. Então cada replica recebe um valor diferente para ReplicaID.

A propriedade DesignMaster também foi criada e indica o Mestre de construção da replica.

A nova propriedade LastUptade armazena o código de identificação do último membro de replicação a atualizar o banco de dados.

Figura 7.0 - AS novas propriedades do banco de dados

Além destas propriedades , cada tabela ganhou nova propriedades. Se você visualizar as propriedades de cada tabela usando Visdata irá perceber isso. Note a propriedade Replicable que tem a mesma função no banco de dados.

É claro que com tantas inclusões o tamanho do banco de dados irá aumentar. Aproximadamente 28 bytes são incluídos para cada registro . Parece pouco mas se considerar todas as tabelas e todos os registros em cada tabela pode ser um aumento considerável. Assim 5 a

Campos de AutoNumeração e replicação em um banco de dados

Um campo autonumeração é um campo incrementado automaticamente pelo sistema de banco de dados , no caso o Jet. Se você pretende replicar o seu banco de dados, é necessário levar em consideração o tamanho de campo apropriado para o campo AutoNumeração utilizado como chave primária da tabela. 

Quando o banco de dados torna-se replicável os campos autonumeração transformam-se em  números aleatórios. Quer ver ? abra uma tabela com um campo autonumeração e insira um novo registro , observe o número  aleatório atribuído ao campo autonumeração...

Criando Réplicas

Toda cópia de um Mestre de Construção é definida como uma réplica. Vamos então criar uma réplica do nosso banco de dados Master.mdb que já esta pronto para ser replicado.

Para criar uma réplica de um banco de dados replicável usamos o método MakeReplica. Sua sintaxe é:

Sintaxe:

database.MakeReplica replica, description, options

Parâmetro Descrição
database Uma variável objeto que representa um um banco de dados existente.
replica Uma STRING que indica o caminho e o nome atribuído a replica criada. 
description Uma String que descreve a replica que estamos criando..
options Opcional. Uma constante ou combinação de constantes que especifica as características da replica . (* veja abaixo as opções)

Podemos ter as seguintes opções no argumento Options:
Constante Descrição
dbRepMakePartial Cria uma replica parcial
dbRepMakeReadOnly Evita a modificação dos objetos replicáveis da nova replica pelo usuário. As alterações somente ocorrerão durante a sincronização com os membros do conjunto de replicação.

Continuando nosso projeto anterior , vamos inserir um novo botão de comando (name=cmdreplica) e digitar  o código abaixo no evento click deste botão:
 
Private Sub cmdreplica_Click()
Dim dbMestre As Database

On Error GoTo trata_erro

Set dbMestre = OpenDatabase(txtcaminho.Text, True)

If dbMestre.Properties("replicable") = "T" Then
    dbMestre.MakeReplica "c:\teste\Mestre_1.mdb", " Replica de " & txtcaminho.Text
    dbMestre.Close
    MsgBox " Foi criada uma copia do banco de dados " & txtcaminho.Text, vbInformation, "Cria Replica"
Else
    MsgBox " Não é possivel criar uma replica para este arquivo ", vbInformation, "Cria Replica"
End If

Exit Sub

trata_erro:
     MsgBox " Erro : " & Err.Description

End Sub

Com o código acima criamos uma réplica do nosso arquivo Mestre.mdb chamada Mestre_1.mdb no diretório c:\teste.

Voce pode abrir a réplica no Visdata e dar uma olhada nas propriedades do arquivo. O arquivo Mestre_1.mdb pode ser usado para , a partir dele, criarmos novas réplicas.

Sincronizando membros de um conjunto de réplicas

Sincronização é o processo de atualização de dois membros de um conjunto de réplicas pelo intercâmbio de todos os registros e objetos atualizados em cada membro. Dois membros estão sincronizados quando as alterações feitas em um deles tiverem sido aplicadas ao outro.

Obs: conjunto de réplicas é a Estrutura-mestre e todas as réplicas que compartilham a mesma estrutura de banco de dados e identificador de conjunto de réplicas exclusivo.

Para realizar a sincronização dos dados entre os membros de um conjunto de réplicas utilizamos o método Synchronize cuja sintaxe é a seguinte:

database.Synchronize pathname, exchange

Onde:

Argumento Descrição
database Uma variável objeto que representa um objeto  Database.
pathname Uma String que contém o caminho para a replica de destino com a qual o banco de dados será sincronizado.
exchange Constante que indica em qual direção a sincronização será realizada.(Opcional)

As constantes para o argumento exchange podem ser:
Constante Descrição
dbRepExportChanges Envia as alterações do Banco de dados para o destino.(pathname)
dbRepImportChanges Envia as alterações do destino (pathname) para o banco de dados.
dbRepImpExpChanges Executa uma troca bidirecional. (É o padrão )
dbRepSyncInternet  Realiza uma troca de dados entre arquivos conectados via internet..

Lembre-se

Antes de fazer a sincronização abra o banco de dados e inclua alguns registros em qualquer tabela. Observe que o campo s_Generation assume o valor zero (0) indicando que o mesmo esta pronto para ser copiado durante a sincronização. 

Private Sub cmdsincronizar_Click()
Dim dbMestre As Database

On Error GoTo trata_erro

Set dbMestre = OpenDatabase(txtcaminho.Text, True)

dbMestre.Synchronize "c:\teste\Mestre_1.mdb", dbRepImpExpChanges

MsgBox " Sincronização realizada com sucesso !", vbInformation, " Sincronização "

Exit Sub

trata_erro:
  MsgBox " Erro : " & Err.Description

End Sub

neste código temos a sincronização entre o banco de dados Mestre.mdb e a replica Mestre_1.mdb. 

Para realizar a sincronização na Internet podemos usar o código abaixo:

Sub Sincronizar_Web()

   Dim dbsTemp As Database

   Set dbsTemp = OpenDatabase("C:\Teste\Internet.mdb")

  
' Sincroniza o banco de dados local com a replica no servidor

   dbsTemp.Synchronize  "www.geocities.servidor.com"  & "/arqs/teste.mdb",  dbRepImpExpChanges + dbRepSyncInternet

   dbsTemp.Close

End Sub

Criando uma Réplica Parcial

É claro que haverá ocasiões onde você não desejará transmitir todo o conjunto de dados do seu mestre de construção para a réplica por razões de segurança. ( quando os dados forem sigilosos(senhas), estratégicos (planejamento) ou confidenciais (dados pessoais) )

Quando isto ocorrer você pode configurar a replicação de modo que somente os dados que você deseja sejam trocados durante o processo de sincronização. Chamamos isto de uma réplica parcial pois copia somente os dados que um certo usuário provavelmente usará.

Uma Réplica Parcial é um banco de dados que não duplica todos os dados no Mestre de Construção. Para criar uma réplica parcial siga as estas etapas :

  1. Use o Método MakeReplica do objeto Database com a opção dbRepMakePartial
  2. Defina a propriedade ReplicaFilter do objeto TableDef para restringir os registros copiados á replica parcial. (Você pode usar uma instrução SQL coma cláusula WHERE)
  3. Defina a propriedade PartialReplica do objeto Relation para restringir os registros copiados com base nas junções entre as tabelas
  4. Execute o Método PopulatePartial do objeto Database para copiar os dados do mestre de construção para a réplica parcial.

Para exemplificar vamos criar uma replica parcial para o banco de dados Mestre.mdb, onde iremos restringir a cópia dos dados da tabela Clientes aos clientes do estado de São Paulo , ou seja , onde  o campo  Estado = "SP" .

1-) Primeiro vamos criar a réplica parcial - veja o código abaixo associado ao um novo botão de comando (name=cmd_cria_replica_parcial). Com isso estaremos um arquivo com a estrutura do Mestre de construção sem dados algum. Os dados virão na segunda etapa: 

Private Sub cmd_cria_replica_parcial_Click()

Dim tabelas As TableDef
Dim dbMestre As Database
Const CaminhoReplica = "c:\teste\Mestre_Parcial.mdb"

On Error GoTo trata_erro

Set dbMestre = OpenDatabase(txtcaminho.Text, True)

dbMestre.MakeReplica CaminhoReplica, "Partial", dbRepMakePartial

MsgBox " Foi criada uma réplica parcial com sucesso !", vbInformation, " Sincronização "
dbMestre.Close

Exit Sub

trata_erro:
MsgBox " Erro : " & Err.Description
End Sub

2-) Executando a réplica parcial e recebendo os dados - Após a replica parcial ter sido criada podemos usar o código abaixo associado a um novo botão de comando ( name = cmd_executa_replica_parcial):

Private Sub cmd_executa_replica_parcial_Click()

Dim tabela As TableDef
Dim dbMestre As Database
Const CaminhoCopia = "c:\teste\copia\CopiaMestre.mdb"

On Error GoTo trata_erro

Set dbMestre = OpenDatabase(CaminhoCopia, True)
Set tabela = dbMestre.TableDefs("Clientes")

'aplica o filtro na tabela
tabela.ReplicaFilter = "ESTADO = 'SP'"

'preenche com os dados do Mestre de Construcao
dbMestre.PopulatePartial txtcaminho.Text

Exit Sub

trata_erro:
MsgBox " Erro : " & Err.Description
End Sub

Resolvendo os conflitos durante a sincronização

Os conflitos podem ocorrer em diversas situações , uma delas seria quando o mesmo registro foi alterado em diferentes replicas entre as sincronizações . Isto poderia atribuir valores distintos para o mesmo registro o que levaria a usuários distintos visualizarem valores distintos para o mesmo registro. Isto também ocorre  quando dois usuários atualizam o mesmo registro em dois bancos de dados diferentes em um conjunto de replicas. A sincronização de dois bancos de dados seria bem-sucedida mas apenas um dos dois conjuntos de alterações seria aplicado a ambos os bancos de dados. 

Os principais tipos de conflitos são:

  1. Conflito de chave única

Um conflito de chave única pode ocorrer em uma das formas a seguir:

  1. Conflito de validação em nível de tabela

Um conflito de validação em nível de tabela ocorre quando são inseridos dados que violam uma regra de validação em nível de tabela que restringe os valores ou tipos de dados que podem ser inseridos em uma tabela. 

  1. Conflito de atualização de integridade referencial

Um conflito de atualização de integridade referencial ocorre quando a chave primária é atualizada em uma réplica e novos registros filho fazem referência ao valor original da chave primária são adicionados a uma réplica diferente.

  1. Conflito de exclusão de integridade referencial

Um conflito de exclusão de integridade referencial ocorre quando um registro de chave primária é excluído em uma réplica enquanto novos registros filho que fazem referência à chave primária excluída são adicionados em uma segunda réplica. 

  1. Conflito de bloqueio

Um bloqueio de conflito ocorre quando o registro não pode ser aplicado durante a sincronização porque outro usuário bloqueou a tabela.

  1. Conflito de violação de chave externa

Um conflito de violação de chave externa ocorre quando há um registro de chave primária inválido. Isso pode ser causado por qualquer um dos outros tipos de conflitos.

A lógica que o Jet Engine usa para resolver os conflitos é a seguinte:

Palavra final

Ao implementar a replicação de um banco de dados você deverá fazer mais de uma cópia do banco de dados original - o Mestre de Construção. Então como e quando atualizar os membros do conjunto de replicação ? Você deve ser criterioso e adotar uma estratégia para fazer isto. 

A topologia mais utilizada ,e talvez a mais simples, para implementar a replicação é a topologia Estrela. Nela temos um banco de dados central ( O mestre de construção ) com o qual todos os membros do conjunto de réplicas realizarão a sincronização. Assim nenhuma replicação será realizada entre os membros do conjunto das réplicas. ( A topologia tem um pequeno problema: quando o banco de dados central estiver fora do ar , ninguém consegue fazer a replicação...)

A topologia Linear também pode ser usada para sincronização das réplicas. Nela a replica A sincroniza com a replica B que sincroniza com a replica C e vice-versa. ( A topologia de Anel é idêntica a Linear..)

Até um próximo artigo...

Veja os Destaques e novidades do SUPER DVD Visual Basic (sempre atualizado) : clique e confira !

Quer migrar para o VB .NET ?

Quer aprender C# ??

Quer aprender os conceitos da Programação Orientada a objetos ?

Quer aprender o gerar relatórios com o ReportViewer no VS 2013 ?

Referências:


José Carlos Macoratti