On Mon, 16 May 2011 19:37:21 +0200, Marco Fochesato <marco...@libero.it> wrote:
> No, niente buchi. > Allora, spieghiamoci così: > siamo di fronte ad un gestionale. come sempre :) > L'utente x parte per compilare un DDT. Problemi con le zanzare? > L'applicazione "prenota" un id (chiave primaria) per il documento. > L'utente y parte anche lui per compilare un DDT. > L'applicazione "prenota" anche per lui un id, lo stesso di quello sopra > (visto che non è ancora stato chiuso, e potrebbe anche darsi che x > decida di non chiuderlo e annullare tutto.. (qui è il nocciolo)). > Il primo che finisce e chiude il ddt, si prende il numero (commit). > Per il secondo, verrà sollevata una eccezzione e verrà concesso un altro > id (non mi interessa qui stabilire come). Non mi sembra il migliore dei comportamenti: perché far fallire la seconda transazione quando ci sono almeno diversi modi di farla riuscire? E se il secondo finisce prima del primo? Dovrebbe fallire il primo? > Quello che mi interessa è la "prenotazione". Se vuoi davvero prenotare un record, puoi inserire un record incompleto oppure tenere una tabella separata delle prenotazioni. Forse anche gli advisory lock possono essere utili. > Io ho bisogno, durante la compilazione del documento, di testare degli > inserimenti, e vorrei che l'applicazione ragionasse come se l'id fosse > inserito. Ma se arriva y, che l'id fosse disponibile anche per lui. Per fare quello che vuoi tu ha ragione Manlio: usare qualcosa tipo max(id) + 1 è la soluzione migliore. Manlio però si è dimenticato di dire di prendere un lock sulla tabella (in pratica gli inserimenti devono essere serializzati): 1) quando il documento viene prenotato: a) prendi un lock sulla tabella che conflitti con se stesso, per esempio "LOCK TABLE blah IN EXCLUSIVE MODE". b) usa come prossimo id "SELECT max(id) FROM blah" c) commit sulla connessione, in modo da liberare il lock. 2) quando il documento viene salvato: a) prendi lo stesso lock sulla stessa tabella b) prendi lo stesso max c) se il max è diverso da quanto registrato, tira un eccezione. O alternativamente scrivi direttamente il max nel database e aspettati un'eccezione se c'è una constraint UNIQUE su quel campo. Questa è un'implementazione pessima di un lock pessimistico: se uno comincia un'operazione, qualunque operazione concorrente è destinata a fallire: perché tu voglia fare questo onestamente mi sfugge. La documentazione sui lock (http://www.postgresql.org/docs/9.1/static/explicit-locking.html) e sul comando LOCK (http://www.postgresql.org/docs/9.1/static/sql-lock.html) può esserti utile. Lasciare aperta la transazione per tutta la durata dell'edit è qualcosa da NON fare. -- Daniele Varrazzo - Develer S.r.l. http://www.develer.com _______________________________________________ Python mailing list Python@lists.python.it http://lists.python.it/mailman/listinfo/python