Newsgroup: it.comp.www.php
Titolo: lock tables

ciao
sto' buttando giu' un piccolo gestionale in Php utilizzando Mysql,
avevo letto che le tabelle MyIsam potevano usufruire del loccaggio
delle medesime, e mi son detto proviamo!
Pero' è un terreno nuovo per me quindi eccomi qui' per essere illuminato
1- ma mi serve veramente bloccare una o piu' tabelle? (direte voi:- E se 
non lo sai tu?!?!?)
2- l'esigenza nasce da un interrogativo ben preciso, se un utente sta 
aggiornando i dati di un cliente come una scadenza, e un altro utente
sta per fare la medesima operazione, accadra' che il primo portera' a 
compimento l'operazione, l'altro si vedra' magari un mex di errore del 
tipo "Amico l'aggiornamento è gia stato effettuato".
A quel punto il secondo operatore potrebbe restare perplesso....
ora pensavo pure alla possibilità (come in joomla) che se un operatore
lavora su un dato quest'ultimo risulta solo leggibile.
In tal caso pero' non so' se joomla utilizza il meccanismo del loccaggio 
delle tabelle, o una procedura gestita interamente da php.
Voi cosa mi consigliate?
loccaggio o una procedura gestita solo da php?
Che magari dica al secondo utente connesso..."attenzione in questo 
momento l'utente TALdeiTALi sta operando sul cliente...".
grazie

 
Gestire la concorrenza sui dati non è semplice e il blocco della tabella 
ti aiuta in parte. Per modificare devi prima accedere ai dati, 
caricarli, mostrarli a video e poi, dopo un certo tempo l'utente può 
aggiornarli. Potresti tenere i dati bloccati per tutto il periodo, dalla 
lettura alla (forse) scrittura ma alla fine, ma ne vale la pena? Un 
utente può modificare solo una parte dei dati e un altro utente l'altra 
parte, alla fine tutte andrebbero salvate.
Per una procedura molto delicata, ho risolto (almeno lo spero) nel 
seguente modo: al momento che mostro a video i dati, mi salvo lo stato 
degli stessi, quando l'utente mi esegue il salvataggio confronto i dati 
originali (salvati precedentemente) con i valori a video, per ogni 
valore diverso, verifico il valore su db [*] se è uguale al valore 
precedente, procedo con la modifica, altrimenti avverto della variazione 
dei dati.
* Durante il confronto eseguo un lock della tabella
	Francesco

Usa le transazioni e le stored procedure, il lock delle tabelle lo decidi 
all'interno delle stored procedure, se non usi il default ( per le transazioni 
le tabelle devono essere InnoDB ).
Per l'aggiornamento dei singoli record usa la tecnica di mettere un numero 
di versione che incrementi ogni qualvolta fai un update; per esempio, l'utente 
A modifica il record 1 con il campo versione che contiene il numero 3, quando 
salva il dato fa un update dei campi 'update tabella set campo1 = 'blabla', 
versione = versione + 1  where versione = 3', se l'update va a buon fine 
vuol dire che nessuno l'aveva toccato e viene anche aggiornata la versione, 
se l'update non tocca nessun record, vuol dire che qualcun ha aggiornato 
prima del salvataggio.
Non so se sono stato chiaro.
Saluti


 tipo "Amico l'aggiornamento è gia stato effettuato".
Attenzione, che il lock non ti serve a prevenire questa situazione, ma 
situazioni ben diverse.
Infatti in questo caso, semplicemente a entrambi gli utenti verrebbe 
mostrato il messaggio "update effettuato" (a meno che non imposti le 
query sincrone, senza attesa, non mi viene il termine esatto...), solo 
che il secondo vedrebbe un leggero rallentamento. Alla fine il risultato 
della data sarebbe quello impostato per ultimo.
Tra l'altro, questo tipo di lock viene gia` effettuato dal DB-engine in 
automatico, altrimenti tutti i DB MySQL sarebbero corrotti, a questo 
punto.
Il locking ti serve per fare cose di questo tipo: blocca la tabella dei 
conti correnti, controlla se nel conto A ci sono piu` di 10.000 euro, 
preleva 10.000 euro dal conto A, versa 10.000 euro nel conto B, sblocca 
la tabella.
Questo per evitare che, per esempio, vengano prelevati contemporaneamente 
10.000 e altri 10.000 euro (da un altro operatore) in un conto che ne ha 
solo 12.000 dentro.
Bye.

tipo "Amico l'aggiornamento è gia stato effettuato".
Questo non e' un table lock, questo e' un record lock. Non tutti i DB lo
hanno.
Normalmente, quando non c'e', viene emulato, o con una colonna LOCKED_BY
in piu', oppure con una tabella extra di record lock:
LOCKS { table varchar, recno sequence_t, locked_by session_t }
A quel punto ti bastano due funzioni speciali che non devono saper nulla
di tutto il resto del database, operano solo su LOCKS (e analogamente il
resto del sistema non sa niente della tabella LOCKS):
	checkout($table, $record_id, $force)
		=> ritorna TRUE se e' riuscita a lockare, se no FALSE
	commit($table, $record_id)
		=> sblocca il record
e modifichi le pagine dove richiedi un record aggiungendo
	if (!checkout($table, $id, false))
	{
		die("Record bloccato");
	}
e quelle dove salvi ed esci aggiungendo l'appropriato commit().
...poi devi risolvere il problema "ma $TIZIO s'e' sloggato, o ha lockato
un record e poi chiuso il browser alla zio diavolo senza fare commit?"
Mi pare che in MySQL con PHP il record lock nativo non sia praticabile o
perche' proprio non c'e', oppure perche' "vive" solo mentre lo script e'
in funzione; e quindi quando l'utente si trova i dati a video, il record
e' di nuovo sbloccato.
GET_LOCK() di MySQL e' usabile, ma se ti rimane un lock impiccato, paghi
pegno.
Leonardo
-- 
While ordinarily valid that being widespread does not make a statement
true, I feel that the diffusion of anti-evolutionary beliefs does pose
a strong argument for Darwin having been, indeed, sorely mistaken.