Jump to content
Sign in to follow this  
pirata11

Transacções PHP+SQL - Lançar alerta documento em edição

Recommended Posts

pirata11

Boa tarde pessoal,

estou com um pequeno problema e não estou a arranjar maneira de dar a volta por cima. Estou a iniciar programação com transacções. Já entendi o conceito e penso que é muito útil. Agora é o seguinte:

Estou a desenvolver um portal em que é possível várias pessoas acederem ao mesmo tempo. Mas queria que enquanto um utilizador estivesse a alterar um documento, outro utilizador receberia uma mensagem a dizer "Este documento já se encontra em edição por utilizador XPTO".

Já vi 2 exemplos em que sei que poderá ser possível fazer isto:

1)SELECT * FROM parent WHERE NAME = 'Jones' LOCK IN SHARE MODE;

2)SELECT counter_field FROM child_codes FOR UPDATE;

UPDATE child_codes SET counter_field = counter_field + 1;

Mas agora, como é que isto funciona ao certo? Agradeço uma ajuda preciosa ;)

Share this post


Link to post
Share on other sites
pirata11

Senão pergunto qual a melhor solução para:

Neste portal, 2 pessoas vão poder alterar a mesma base de dados. Essas pessoas não estão em contacto logo não sabem se alguém está a alterar alguma coisa ou não. Como faço para lançar um alerta ao utilizador 2 a dizer "ATENÇÃO: O UTILIZADOR 1 ESTÁ A EDITAR A BASE DE DADOS!".

Achei que com transacções isto funcionaria, mas não consegui nada :/

Ajuda para outra solução p.f. (Não usar Javascript pf)

Share this post


Link to post
Share on other sites
laboss

Porque que ao entrar na edição da noticia nao inseres numa tabela a parte tipo:

edicoes_curso

id da noticia

id do user

inicio edicao

ao entrares na edicao inseres um registo nessa tabela, ao guardar removes, depois imagina que o utilizador edita mas nao submete, isto iria originar que a noticia tivesse bolqueada para sempre ate tu removeres o registo, podes definir um tempo e sempre que fores editar ao chamares a rotina para ver se ja ta a ser editadas apagas os registos onde a data de inicio edicao sejam maiores que 1/2h assim por alto claro, podias apagar os registo de edicao quando o utilizador fizer logout tambem, e apenas uma ideia ;)

Share this post


Link to post
Share on other sites
xester

Dependendo do CMS que usas podes integrar o query da SQL na edição para uma tabela a dizer que alguém está aditar, algo que o laboss disse. Mas por PHP fazendo query retirava trabalho por exemplo ir ao phpmyadmin e fazer, portanto.

Criavas uma Tabela a Dizer em cada entrie: A ser editado por: XXXX

Se alguém não o tivesse a editar, deixavas completamente em branco deforma a não mostrar quando fizesses a query á entrada do artigo

mysql_query("SELECT * FROM artigo WHERE `artigo`.`editado` = 'A ser editado por: XPTO';")

isto um exemplo rapido :X pode conter erros

Share this post


Link to post
Share on other sites
pirata11

Essa ideia acho que é a que vem primeiro à cabeça de qualquer um. O problema mesmo é que este portal é para uma empresa com dezenas de trabalhadores, ou seja, ainda é mais utilizador que a compra de bilhetes na ryanair :/

A ideia de usar uma tabela auxiliar e do tempo poderá não ser fiável. Se eu definir por exemplo 1/2 hora para edição, o utilizador 1 poderia demorar 45 minutos para editar, e o utilizador 2 entraria ao fim de 40 minutos logo, entre os 30mins e os 45 de edição não apareceria qualquer mensagem ao utilizador 2.

Caso o utilizador 1 começasse a editar e clicasse em cancelar ou logout, isso era fácil e estaria resolvido. Mas imaginem caso o utilizador a meio da edição fechasse a janela acidentalmente? O registo ficaria na tabela a dizer que estava em edição.

O ideal seria mesmo usar a variavel do apache do timeout. Porque quando eu clico no [X] para fechar a janela e a seguir volto a abrir o portal, isto volta a pedir o login. Portanto seria fixe que ao clicar no [X] isto eliminasse o registo da tabela. É possível?

Share this post


Link to post
Share on other sites
taviroquai

Mas imaginem caso o utilizador a meio da edição fechasse a janela acidentalmente? O registo ficaria na tabela a dizer que estava em edição.

É mesmo para esses casos que serve o tempo em que expira a edição. Sempre que o utilizador estiver a trabalhar na edição, a cada pedido da página, actualizas o tempo de inicio da edição. Se por acaso, fechar a página e outro utilizador quiser editar, aí comparas se já expirou o tempo de edição e até podes devolver esse tempo ao utilizador e dizer: Registo em edição. Tente novamente daqui a X minutos. Isto é seguro.

Na pior das hipoteses, vai ficar o registo marcado como a ser editado durante os X segundos (tempo em que expira a edição) e ninguém poderá editá-lo, mas pelo menos não existem 2 utilizadores a editar o mesmo registo ao mesmo tempo.

Share this post


Link to post
Share on other sites
pirata11

E como faço essa comparação? qual a variavel de timeout do php/apache?

Share this post


Link to post
Share on other sites
morsa

Boas! :)

O problema que descreves tem a ver com dead locks. A única solução que encontrei é uma questão de compromisso. Do que percebi, dois utilizadores tentam aceder a um determinado ficheiro ou item e tu tens que bloquear a edição, correcto?

Analisando:

- Utilizador 1 abre o ficheiro a.txt;

- Inseres numa tabela auxiliar algum:

insert into edicao(idUtilizador, idFicheiro) VALUES (1, 1); 

em que o idFicheiro é a chave do ficheiro (de uma suposta tabela de ficheiros) - podes também usar o nome do ficheiro, como quiseres :)

- Utilizador 2 quer abrir o ficheiro a.txt;

- Pesquisas na tabela edicao

 select count(idFicheiro) from edicao where idFicheiro = 1;

  - a pesquisa devolve-te 1 logo não pode editar o ficheiro.

  - informas o utilizador 2 disso mesmo;

  - se o count devolver  1 ele está em edição logo verificas se o utilizador ainda está  na sessão

    select DataLogout from utilizadores where idUtilizador = (select idUtilizador from edicao where idFicheiro = 1)

  - se a DataLogout estiver preenchida é porque existe um dead lock... faz um delete da linha :)

O problema do dead lock:

O Utilizador 1 fechou o browser acidentalmente/terminou sessão sem que desbloqueasse o ficheiro.

- Aqui, a solução que vejo é Javascript. O método document.close do DOM do javascript é invocado aquando o fecho do documento. Podes fazer uma chamada AJAX para desbloquear todos os ficheiros bloqueados pelo utilizador:

DELETE from edicao where idUtilizador = 1;

Desse utilizador, deves ainda terminar a sessão do utilizador! Isto é importante.

Existe ainda outro problema que não sei se te ocorreu: "O PC crashou, o browser bloqueou..." - com a abordagem que descrevi -

O browser nunca vai chamar o document.close dessa janela. Entao, e aqui está o compromisso de que falava:

- se a tua arquitectura estiver feita desta forma:

  - utilizador faz login -> actualizas a data de login do utilizador -> actualizas a data de logout para NULL -> geras a sessão --- então verificas da seguinte forma:

  - crias um Cron Job, por exemplo, de 5 em 5 minutos, que verifica se existem documentos bloqueados de utilizadores que já terminaram sessão que executa a verificação dos Dead Lock's; basta fazeres um ficheiro PHP que execute o SQL abaixo (ou até mesmo um ficheiro SH - isto, em Linux).

delete edicao where idUtilizador in select idUtilizador from utilizadores where DataLogout > CURRENT_TIMESTAMP

A última e derradeira solução é teres um administrador que possa remover estes Dead Locks, por exemplo, uma listagem de ficheiros (da tabela aux. edicao) em que podes desbloquear os ficheiros

Espero ter ajudado! Boa sorte!

1abraço

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
Sign in to follow this  

×
×
  • Create New...

Important Information

By using this site you accept our Terms of Use and Privacy Policy. We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.