Conteúdo

- Redes - Programas Multiusuários


Hoje vamos falar sobre redes e programação multiusuário.

Introdução.

Mesmo que você não desenvolva sistemas para um ambiente de rede, precisa saber 
alguns conceitos relativos ao assunto.
Naturalmente o Visual Basic fornece acesso compartilhado ao banco de dados do 
sistema e vários usuários poderão acessar  os dados ao  mesmo tempo; o  VB faz o
bloqueio e o desbloqueio das páginas dos dados quando necessário, automaticamente.

Se você quiser que os dados de sua aplicação sejam acessados por um único usuário,
este é o modo exclusivo , terá que informar isto ao VB.

Para abrir um arquivo de dados no VB usamos o método OpenDatabase, vejamos então 
sua sintaxe:

Set database = workspace.OpenDatabase(dbname[, exclusive[, read-only[, source]]]

Observe o argumento opcional exclusive , ele pode assumir dois valores: 

-True   -  Abre o arquivo no modo exclusivo , ou seja , não compartilhado.
-False  -  Abre o arquivo no modo compartilhado.

Se você omitir este argumento o arquivo é aberto no modo compartilhado.

O argumento read-only também pode assumer dois valores:

-True  - Abre o arquivo no modo read-only , isto é, somente leitura.
-False - Abre o arquivo no modo read/write , isto é , leitura e escrita.

Se voce omitir este argumento o arquivo é aberto no modo leitura e escrita.

Portanto se você usa a seguinte sintaxe para abrir um banco de dados do seu 
sistema: 

dim db as database
set db = dbengine.workspaces(0).OpenDatabase(app.path & "\nome_arquivo")

O seu arquivo estará sendo aberto no modo compartilhado. Até aqui tudo bem !

Conteúdo

O acesso aos Dados.

O limite mais restritivo que podemos impor a um banco de dados é sua abertura 
em modo exclusivo.

Isto impedirá que qualquer usuário tenha acesso ao banco de dados enquanto ele 
estiver sendo utilizado.(Isto inclui todas as suas tabelas e consultas.)

Vejamos a sintaxe utilizada para este caso:

dim db as database
set db = dbengine.workspaces(0).OpenDatabase(app.path & "\nome_arquivo",True)

A tentativa de abrir o arquivo em uso irá gerar uma mensagem de erro pelo VB.

Quer algumas boas razões para usar o  acesso exclusivo ?

Use-o em operações que afetem todo o banco de dados tais como:

-Compactação do banco de dados
-Atualização de tabelas inteiras
-Alteração da estrutura do banco de dados(inclusão de tabelas, índices, etc...)

Se você não quiser ser tão radical, pode restringir o acesso á tabela em 
uso pelo seu sistema.

Para fazer isto utilizamos as opções do método OpenRecordSet para negar 
acesso de leitura e/ou gravação ás tabelas , vamos a sua sintaxe:

Set variable = database.OpenRecordset(source[, type[, options]])

Vejamos as opções mais usadas:

-dbDenyRead    Impede os usuários de examinar os dados contidos na tabela,até você fechá-la.
               (Disponível para recordsets do tipo tabela)

               Você usuará esta opção quando for necessário atualizar informações na tabela inteira.

               Ex: Dim db as database,rs as recordset
                   set rs=db.openrecordset("nome_tabela",DbOpenTable,dbDenyRead)
                   
-dbDenyWrite   Os usuários podem visualizar os dados mas não podem atualizar as informações da tabela, 
               nem incluir novos registros ,até você fechá-la.(Válido para Tabelas,Dynasets e Snapshot)

               Você pode usar esta opção quando estiver incluindo novos registros na tabela e não 
               houvesse modificações nos registros existentes.               

               Ex: Dim db as database,rs as recordset
                   set rs=db.openrecordset("nome_tabela",DbOpenTable,dbDenyWrite)

-dbReadOnly    Permite somente visualizar os dados da tabela.
               Ex: Dim db as database,rs as recordset
                   set rs=db.openrecordset("nome_tabela",DbOpenTable,dbReadOnly)

               Você pode usar esta opção em tabelas de pesquisa.

               Uma outra maneira de restringir o acesso a apenas leitura , é utilizar 
               Snapshots.Eles sempre são de somente leitura.
               A vantagem dos Snapshots é que eles ficam armazenados na memória.
               Ex: Dim db as database,rs as recordset
                   set rs=db.openrecordset("nome_tabela",DbOpenSnapshot)

-dbAppendOnly  Permite somente a inclusão de novos registros(Válido somente para dynaset)
               Ex: Dim db as database,rs as recordset
                   set rs=db.openrecordset("nome_tabela",DbOpenDynaset,dbAppendOnly)

Se você tentar abrir qualquer tabela com as restricões acima mencionadas e um outro 
usuário já estiver com ela aberta ocorrerá uma mensagem de erro.

Dai conclui-se que o código de tratamento de erros deverá ser utilizado em todos 
os lugares onde o método OpenRecordset for utilizado, pois neste caso o método
falhará e você tem que estar preparado para interceptar o erro gerado.

Que tal provarmos tudo isso ? Então vamos lá...

-Primeiro vejamos um exemplo para o caso da abertura do banco de dados nos modos 
 exclusivo e compartilhado :
 - Acesso Exclusivo/Compartilhado.

-A seguir um exemplo que analisa o comportamento do Jet na abertura das tabelas 
 nas  opções dbDenyRead , dbDenyWrite e dbReadOnly : 
 - Acesso as tabelas - dbDenyRead , dbDenyWrite e dbReadOnly

Nota :Da mesma forma você pode usar as opções descritas acima para criar um dynaset.
      Ex: Para criar um dynaset com a opção dbDenyWrite
        
Set rs = db. OpenRecordset("SELECT * FROM Tabela", DbOpenDynaset, dbDenyWrite) 
        
Conteúdo 

Bloqueio de Registros

Se sua aplicação for rodar em um ambiente multiusuário mais cedo ou mais tarde
alguém tentará atualizar um registro que está bloqueado por outro usuário ou 
outro usuário tentará modificar um registro que você esta atualizando. E ai...?

Antes de fazer um pedido para editar um registro já existente ou incluir um novo 
registro,  o Jet irá verificar se nenhum outro usuário esta tentando modificar o
registro ou acrescentando um registro novo , para isso o Jet utiliza a técnica de
bloqueio de registros.

Mas atenção , o jet na não aceita o bloqueio de registros , na verdade o que
ocorre é o bloqueio da página ou páginas contendo o registro. Como uma 
página contém 2K (2048 bytes), o bloqueio será efetuado não somente no registro
desejado mas também nos adjacentes , a não ser que o registro tenha exatamente o
tamanho de 2048 bytes.

O jet trabalha então com dois métodos de bloqueios : o pessimista e  o otimista.
Vejamos cada um deles:

1-Bloqueio pessimista(O padrão usado pelo VB)

 Executa o bloqueio da página que contém o registro no momento que sua aplicação
 executar o método Edit

 O registro permanecerá bloqueado até ser executado o método Update e os dados 
 forem gravados no arquivo. 

 Perceba que enquanto você estiver editando o registro outros usuários não poderão 
 alterá-lo. Se alguém tentar bloquear a página que contém o registro o Jet retornára 
 um erro.

 A desvantagem do bloqueio pessimista é que se você bloquear o registro para edição
 por um período longo , ninguém mais conseguiria editar o mesmo registro e os outros 
 registros da mesma página além de afetar o desempenho do sistema.

2-Bloqueio otimista

 Executa o bloqueio da página contendo um determinado registro somente quando for
 invocado o  método Update.

 O bloqueio é imediatamente liberado quando se completa a operação de atualização.

 A vantagem é que a página é bloqueada por um curto período de tempo.

 A desvantagem é a possibilidade de outro usuário alterar os dados contidos no 
 registro entre os instantes em que são empregados os métodos Edit e  Update,
 se isto ocorrer o Jet retorna um erro.

Com isto em mente você deve levar em conta algumas considerações ao utilizar o bloqueio
de registros. Vejamos :

1-O que fazer caso não seja possível bloquear um registro.
2-Como evitar que o usuário mantenha um registro bloqueado por muito tempo.
3-Determinar qual tipo de bloqueio usar: pessimista ou otimista
 
No primeiro caso temos os conflitos de bloqueio, ou seja, se um usuário 
bloqueou um registro e outro usuário requisitou um bloqueio no mesmo registro 
ocorrá um erro.

Como o VB não fornece uma maneira de verificar se um registro está bloqueado, 
você tem que estar preparado para os erros de bloqueio implementando um código
de tratamento de erros em todos os lugares onde irá acrescentar ou atualizar os 
registros.

Dentre os inúmeros erros que o Jet retorna em ambiente multiusuário existem 3 que
são muito importantes e deles você deve se proteger,  vejamos :

-Erro 3167 - O registro foi deletado

             Lembre-se que as modificações(alterações,exclusões,etc..) feitas
             em um registro somente serão refetidas em um dynaset quando
             o VB reler a página que contém o registro.       

             Neste caso o erro ocorre quando você tentar executar o método
             Edit em um registro que já foi deletado por outro usuário
             desde a última vez que você leu a página.

-Erro 3197 - Os dados foram modificados; a operação foi interrompida.
             Ocorre quando você tenta editar um registro que sofreu modificações
             por outro usuário desde a ultima vez que você leu a página.

-Erro 3260 - Impossível atualizar; atualmente bloqueado pelo usuário x 
             na máquina y.
             Ocorre quando você tenta bloquear uma página que já está bloqueada
             por outro usuário.

Quanto ao método de bloqueio a utilizar , na maior parte dos aplicativos de banco
de dados, o bloqueio otimista é a melhor opção , mas existirão situações em que 
você deverá usar o bloqueio pessimista.

Para estabelecer o método de bloqueio de registro, defina a propriedade LockEdits
da tabela ou do dynaset com que está trabalhando. Assim :

1-Produzir bloqueio Pessimista - LockEdits = True 

  Dim rs as Recordset
  rs.LockEdits = True  

1-Produzir bloqueio Otimista - LockEdits = False 

  Dim rs as Recordset
  rs.LockEdits = False

Como dissemos a liberação do bloqueio é automática, mas em aplicativos com intensa
entrada de dados você pode precisar fazer pausas momentâneas no processamento do 
aplicativo para permitir ao Jet realizar o seu trabalho de manutenção; para isto 
utilizar o método Idle, da seguinte forma:

 DbEngine.Idle dbFreeLocks 

Conteúdo

Por enquanto é só. Retornarei ao assunto , aguardem !
 
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 ?

Quer aprender a criar aplicações Web Dinâmicas usando a ASP .NET MVC 5 ?


José Carlos Macoratti