problema de registros em branco no dbf.

Fórum sobre a linguagem CA-Clipper.

Moderador: Moderadores

Avatar do usuário
Maligno
Membro Master
Membro Master
Mensagens: 6398
Registrado em: 06 Jul 2004 01:40
Localização: Londrina/PR

Mensagem por Maligno »

Eolo escreveu:Imagine a seguinte situação: eu tenho o arquivo CLIENTES.dbf, indexado por nome, que NÃO PODE ter nomes duplicados e que PODE ser atualizado por todas as estações da rede.
Respondo com uma pergunta: em que situação duas estações numa rede poderiam incluir um mesmo nome ao mesmo tempo?

[]'s
Maligno
http://www.buzinello.com/prg
MARCELOG
Usuário Nível 4
Usuário Nível 4
Mensagens: 546
Registrado em: 15 Mar 2005 16:54
Localização: Divinópolis/MG

Mensagem por MARCELOG »

É........
De novo o Maligno está certo.
Rlock(), relativamente ao usuário atual, sempre retorna .t. se o registro já estiver travado por ele mesmo.
Então, Scom, muito embora não seja o recomendado, o seu if rlock() no lugar de if neterr() não está criando ou fazendo com que o registro fique em branco.
Dá uma olhada nesta função que você usa, talvez ela esteja retornando .f. (falso) e o problema esteja nela.

MarceloG
Avatar do usuário
Eolo
Colaborador
Colaborador
Mensagens: 1134
Registrado em: 08 Dez 2005 18:24
Localização: São Paulo - SP

Mensagem por Eolo »

Maligno,

Isso acontece em todos os meus clientes. Por ex., duas estações podem incluir nomes (on the fly) no mesmo ACLIE.dbf:
- a estação A entra com o suposto novo nome (GETs)
- se o usuário manda gravar, eu rodo o FLOCK()...
(nessa hora, o arquivo continua disponível, pra consulta, na estação B)
... e SEEK no nome. Se já existir, UNLOCK e mensagem de erro na tela. Se não existir, APPEND, COMMIT e UNLOCK.

Se as duas estações tentaram incluir um novo nome ao mesmo tempo, uma vai ter que esperar, mas isso é coisa de fração de segundo...

Mesma coisa pra vendas (onde eu uso uma seqüência numérica): cada estação "monta a venda" em GETs (clientes, produtos, etc) e, para gravar, é uma de cada vez, pegando o próximo número sequencial disponível.
Avatar do usuário
Maligno
Membro Master
Membro Master
Mensagens: 6398
Registrado em: 06 Jul 2004 01:40
Localização: Londrina/PR

Mensagem por Maligno »

Eolo escreveu:Isso acontece em todos os meus clientes. Por ex., duas estações podem incluir nomes (on the fly) no mesmo ACLIE.dbf:
- a estação A entra com o suposto novo nome (GETs)
- se o usuário manda gravar, eu rodo o FLOCK()...
(nessa hora, o arquivo continua disponível, pra consulta, na estação B)
... e SEEK no nome. Se já existir, UNLOCK e mensagem de erro na tela. Se não existir, APPEND, COMMIT e UNLOCK.
Tudo bem. A questão que levantei era pra se pensar na necessidade do travamento do arquivo. Acho que necessidade real não existe. Raciocine comigo. Se, no momento que antecede a gravação, você pesquisar pelo nome que está para ser incluído e ele não existir, qual é a possibilidade dele ser incluído noutra estação na fração de segundos que a gravação tomará? A possibilidade é pequena. Muito pequena.
Por outro lado, se há situações em que dois nomes poderiam ser incluídos ao mesmo tempo, de duas uma: ou a empresa é muito mal organizada ou, havendo uma boa justificativa para isso, você teria de ser muito azarado para que a duplicidade ocorra.
Eu tenho situações assim. Não com relação ao nome, mas ao CNPJ. Um fornecedor, por exemplo, deverá ser único. Jamais travo o arquivo todo. No momento que antecede a gravação eu busco pelo CNPJ. Não existindo, gravo. Se existir, páro e aviso da duplicidade. Isso nunca acontece, mas tomo esse cuidado. E só. Já é suficiente. É extremamente remota a possibilidade de ocorrer duplicidade. Não só pela característica (não é toda hora que incluem fornecedores) mas também, e principalmente pela estatística que, neste caso, está a meu favor.

Por outro lado, se você travar o arquivo todo por conta de uma simples inclusão, dependendo da rede, você estará "matando" a performance das demais estações. Isso tudo motivado por um medo injustificado, ou excesso de zelo, como queira chamar. :)

É claro que eu não quis dizer que o seu procedimento para resolver este problema está errado. É a sua forma de resolvê-lo.

[]'s
Maligno
http://www.buzinello.com/prg
Avatar do usuário
Pablo César
Usuário Nível 7
Usuário Nível 7
Mensagens: 5312
Registrado em: 31 Mai 2006 10:22
Localização: Curitiba - Paraná

Mensagem por Pablo César »

Você escrevem muito rápido... Eu ja estava até fazendo exemplo de fonte sobre essa questão. Mas foi sintetizada em algumas palavras.

Caro Eolo, concordo com o Maligno e até considero viável a implementação de verificar após os GETS serem prenchidos, verificar TAMBÉM se aquele CPF (digamos) existe ou não. Seja na hora da edição do GET VCPF como TAMBÉM na hora que for fazer o APPEND BLANK no arquivo. Agora, se mesmo assim houver duplicidade, isto é, no meio tempo de um APPEND BLANK e seus devidos REPLACEs numa outra estação... realmente é muito incomum tanta conincidência. Mas a pior das hipóteses, o usuário mesmo que tenha passado pelo prenchimento do GET VCPF e chegue na hora de gravar, o sistema dirá que não poderá incluir este cliente, porque ACABOU de ser incluso por outro terminal (se quiser dá o nome da estação/usuário).

Mas utilizar o FLOCK(), você estaria amarrando muito as alterações do arquivo. Você mesmo falou que discordava na hora apenas de MODIFICAR registro. Mas se você utilizar o FLOCK(), vai deixar muita gente sem poder gravar nada nesse arquivo. Entendo que a necessidade de inclusão UNIQUE seja até digamos necessária de verificação. Mas como dizemos, pode ser feita duas vezes (na edição do GET VCPF) e na hora que deveria fazer o APPEND BLANK (faça novamente a pesquisa).

Bem essa é também a minha opinião.

Um clip-abraço :)Pos
Avatar do usuário
Pablo César
Usuário Nível 7
Usuário Nível 7
Mensagens: 5312
Registrado em: 31 Mai 2006 10:22
Localização: Curitiba - Paraná

Mensagem por Pablo César »

Eolo escreveu:Mesma coisa pra vendas (onde eu uso uma seqüência numérica)
Para estes casos Eolo, ja foi abordado aqui no FORUM, que o ideal era fazer um arquivo separado onde contivesse tal numeração e que seria pego em cada inclusão, tratando este arquivo normalmente como todo DBF, con RLOCK() e REPLACE.

Sei que você irá me dizer... e se houver desistência de inclusão ?. Eu responderia: Também você pode fazer uma rotina de retorno daquele número que foi pego, para que não sejam pulados os numeros. Creio que eu comentei naquele tópico que eu utilizava dois campos INICIO e FIM e quanto era devolvido um número bastava fazer um APPEND BLANK e ter este arquivo de sequências ORDENADO (com arquivo de indice).

Eolo, também quando você menciona em questão de NOMES de clientes:
Se as duas estações tentaram incluir um novo nome ao mesmo tempo, uma vai ter que esperar, mas isso é coisa de fração de segundo...
Nem sempre uma inclusão é rápida. E também terás que tomar em conta, que as vezes existem NOMES iguais mas são pessoas diferentes (acho que se diz ONÔNIMOS). Neste caso você terá que perguntar ao usuário e/ou comparar com o CPF, caso tiver. Porque com o RG... não dá para obter um identificação padronizada (assim como CPF, CNPJ, etc..).

Mas de todas formas, valeu Eolo, fica aqui registrado todas essas questões, que todo mundo se pergunta.
Um clip-abraço :)Pos
Avatar do usuário
Eolo
Colaborador
Colaborador
Mensagens: 1134
Registrado em: 08 Dez 2005 18:24
Localização: São Paulo - SP

Mensagem por Eolo »

Pablo / Maligno:

- estatísticamente pode até ser pouco provável, mas um sistema qq de controle, a meu ver, não é pra ficar em possibilidades. Pra que correr risco ou ter que retificar depois?

- quanto ao FLOCK() "matar a performance das demais estações", é só fazer um teste, calcular quanto tempo demora entre o FLOCK() e o UNLOCK, passando pelo SEEK, os REPLACEs e o DBCOMMIT(). É quase zero...

- o arquivo FLOCK()ado fica disponível, o tempo todo, para consultas a partir de outros terminais, ele não fica "bloqueado" como no caso do EXCLUSIVE.

- estatisticamente é muito pouco provável que digamos 30 estações, todas exatamente às 12:15:01hs, teclem ENTER para incluir 30 novos clientes... E, mesmo se acontecer, quanto vai demorar pra última conseguir completar a operação? 30 segundos?


Se, enfim, não é nada disso, pra quê afinal o FLOCK() foi criado?
Avatar do usuário
Maligno
Membro Master
Membro Master
Mensagens: 6398
Registrado em: 06 Jul 2004 01:40
Localização: Londrina/PR

Mensagem por Maligno »

Eolo escreveu:- estatísticamente pode até ser pouco provável, mas um sistema qq de controle, a meu ver, não é pra ficar em possibilidades.
Muito do que se faz em programação tem profunda relação com estatística. É como no caso dos algorítmos hash. Não há quem garanta que nunca existirão dois conjuntos de dados que gerem o mesmo MD5, por exemplo. Confia-se na estatística. Ela é um "alento" suficiente.
- quanto ao FLOCK() "matar a performance das demais estações", é só fazer um teste, calcular quanto tempo demora entre o FLOCK() e o UNLOCK, passando pelo SEEK, os REPLACEs e o DBCOMMIT(). É quase zero...
Concordo discordando. :)
Existem situações em que isso não é nada crítico. Pode-se travar o arquivo sem prejuízo para os demais. Mas numa rede em que há muita concorrência pelo mesmo arquivo, travá-lo poderia significar uma importante degradação da performance.
- estatisticamente é muito pouco provável que digamos 30 estações, todas exatamente às 12:15:01hs, teclem ENTER para incluir 30 novos clientes... E, mesmo se acontecer, quanto vai demorar pra última conseguir completar a operação? 30 segundos?
Dependendo da situação, 30 segundo é algo inaceitável. Cada caso é um caso.
Se, enfim, não é nada disso, pra quê afinal o FLOCK() foi criado?
Volto a repetir: cada caso é um caso. E há casos em que o FLock() tem serventia.
Aliás, ninguém aqui quer demonizar a função FLock(). Eu, pelo menos, só quero frizar que em muitos casos (a maioria, acredito), o travamento de um arquivo é totalmente desnecessário. Técnicas alternativas tem na estatística uma garantia mais que suficiente de que as duplicidades não ocorrerão.
Aliás, lembro de um caso meu que já citei anteriormente: meus códigos internos são simples números aleatórios. A estatística me garante a unicidade destes códigos. Elimino a necessidade de manter seqüências de códigos em arquivo e fico tranqüilo sabendo que eles nunca se repetirão.

[]'s
Maligno
http://www.buzinello.com/prg
Avatar do usuário
Pablo César
Usuário Nível 7
Usuário Nível 7
Mensagens: 5312
Registrado em: 31 Mai 2006 10:22
Localização: Curitiba - Paraná

Mensagem por Pablo César »

Eolo escreveu:pra quê afinal o FLOCK() foi criado?
Para o Eolo usar nas suas inclusões..... hehehe
:D

Nas escrituras, menciona o uso para:

1. DELETE ALL FOR DEPTO="DIRETORIA"
2. INDEX ON (quando não é de modo exclusivo)
3. PACK
4. REPLACE ALL
5. SORT
6. UPDATE
7. RECALL ALL

Inclusive o ZAP, só pode ser usado em modo EXCLUSIVO. Mas Eolo, então quer dizer que você ainda não concorda com a sugestão de verificar duas vezes (seja na edição daquela variavel pertencente ao campo chave) como também ANTES de executar o comando APPEND BLANK ?.

Mas se o seu cliente está satisfeito... é o que verdadeiramente importa... :)Pos
Avatar do usuário
sygecom
Administrador
Administrador
Mensagens: 7131
Registrado em: 21 Jul 2006 10:12
Localização: Alvorada-RS
Contato:

Mensagem por sygecom »

Gente.......isso tudo deve ter dado um NÕ na cabeça do SCOM que até agora o cara não apareceu pra dizer como ele resolveu...o problema.....

Agora soh resta Espera...

Abraços
Leonardo Machado
Leonardo Machado
xHarbour.org + Hwgui + PostgreSql
Avatar do usuário
Maligno
Membro Master
Membro Master
Mensagens: 6398
Registrado em: 06 Jul 2004 01:40
Localização: Londrina/PR

Mensagem por Maligno »

sygecom escreveu:até agora o cara não apareceu pra dizer como ele resolveu...o problema.....
Mas toda essa discussão paralela não foi pra tentar resolver o problema dele. Ela aconteceu à parte da discussão do problema original.
E outra: se ele conseguiu resolver, ótimo. Felizes para sempre. Senão ele volta e diz que ainda não foi possível resolver. Daí a gente pensa noutra coisa. Simples. :)

[]'s
Maligno
http://www.buzinello.com/prg
Avatar do usuário
Eolo
Colaborador
Colaborador
Mensagens: 1134
Registrado em: 08 Dez 2005 18:24
Localização: São Paulo - SP

Mensagem por Eolo »

Pablo,
Po, e eu sem saber que o FLOCK() foi feito só pra mim! Agora é que não páro mais de usar ele. E mais: vou passar a cobrar royalties! eh eh eh
Avatar do usuário
momente
Usuário Nível 3
Usuário Nível 3
Mensagens: 496
Registrado em: 03 Mar 2005 11:53
Localização: São Carlos-SP
Contato:

Mensagem por momente »

Concordo plenamente com o amigo Marcelog!

Valeu!
Rogerio L. Momenté
Nada é tão perfeito que não possamos melhorar.
Nunca se explique. Seus amigos não precisam e seus inimigos não vão acreditar.
www.looksystem.com.br
Avatar do usuário
Pablo César
Usuário Nível 7
Usuário Nível 7
Mensagens: 5312
Registrado em: 31 Mai 2006 10:22
Localização: Curitiba - Paraná

Mensagem por Pablo César »

kakaka ! Imagem´

Tá louco ! Aí que eu estou ferrado...

Mas falando sério agora, percebeu que essa função de FLOCK(), está relacionada com outros comandos (os que eu listei) e que não são muito utilizados em rede. Se eu tiver que deletar um bloco de registros funcionando em rede, eu preferiria fazer um DO WHILE com tal condição e fazer um RLOCK() para cada registro a ser deletado, que é mais flexível do que usar o FLOCK() ou USE EXCLUSIVE para fazer um DELE ALL... Em arquivo extremamente grandes iria demorar muito também.

Enfim, como eu disse, é importante você ter levantado esta questão, ora eu ja mesmo ja me questionei disto e creio que alguns devem revisar tais conceitos. Não estou querendo impor nada, mas sabe... qualquer ação implica numa reação...

Um clip-abraço e desculpa a minha brincadeirinha (eu sei que você gosta de polemizar certos assuntos) principalmente quando dão margem a muitas opções. :)Pos
scom
Usuário Nível 3
Usuário Nível 3
Mensagens: 133
Registrado em: 15 Nov 2004 10:49
Localização: Dourados/MS

meus amigos....que susto que tomei...

Mensagem por scom »

meus amigos...estava meio corrido por aqui...e quando entrei no forum novamente tomei um baita susto, com tantas respostas sobre o assunto.

vcs são realmente D+....e com tudo isso eu tirei muito proveito, como por exemplo que o append blank ja bloqueia e não preciso usar o rlock(), então vou mudar minhas funções de adicionar registros, pois eu faço assim:

GETS....
READ
IF LASTKEY()<>27
if ADI_REGI()
IF REG_LOCK()
REPLACE A_CODI WITH CODI,A_DESC WITH DESC,ETC.....
ENDIF
ENDIF
DBUNLOCK()
DBCOMMIT()
ENDIF


FUNCTION ADI_REGI

PRIVATE oERRO
APPEND BLANK
oERRO = NETERR()
DO WHILE oERRO
MENS('Tentando Gerar Novo Registro...'+TRIM(ALIAS()))
INKEY(2)
APPEND BLANK
oERRO = NETERR()
ENDDO
IF oERRO
MSGBOX1('Registro nao foi acessado.')
CLOSE DATA
RETURN(.F.)
ELSE
RETURN(.T.)
ENDIF

FUNCTION REG_LOCK
PRIVATE oERRO
oERRO = RLOCK()
DO WHILE .NOT. oERRO
MENS('Tentando acessar registro...Arq '+TRIM(ALIAS()))
INKEY(2)
oERRO = LOCK()
ENDDO
IF .NOT. oERRO
MSGBOX1('Registro nao foi acessado.')
RETURN(.F.)
ELSE
RETURN(.T.)
ENDIF

ENTÃO EU SÓ PRECISO USAR O ADI_REGI(). BELEZA.

MAS É O SEGUINTE EU CONSEGUI ACHAR O PROBLEMA E NÃO ERA RELACIONADO COM APPEND BLANK E SIM COM SEEK.

EM UM DETERMINADA HORA EU TINHA QUE ATUALIZAR O CADASTRO DE PRODUTOS E FAZIA ASSIM:

SELE PRODUTOS
SEEK CODI
IF REG_LOCK()
REPLACE ........
ENDIF
DBUNLOCK()
DBCOMMIT()


OU SEJA EU NÃO USAVA O !EOF() E O CODIGO POR EXEMPLO NÃO ERRA ENCONTRADO E ELE CRIAVA UM REGISTRO EM BRANCO.

AI PASSEI A FAZER ASSIM:

SELE PRODUTOS
SEEK CODI
IF !EOF()
IF REG_LOCK()
REPLACE.....
ENDIF
DBUNLOCK()
DBCOMMIT()
ENDIF


QUE DOR DE CABEÇA....FIZ O TESTE E REALMENTE ELE ADICIONAVA UM REGISTRO EM BRANCO.


MUITO OBRIGADO A TODOS VOCÊS....VOCÊS SÃO SHOW DE BOLA..


VALEU

ATÉ A PROXIMA

ROBSON
S COM INFORMÁTICA
CLIPPER 5.3 / FIVEWIN 2.0 / BLINKER 7
XHARBOUR/ BCC582
Responder