2015-03-11 19 views
8

Ho una funzione che deve eseguire un aggiornamento lungo su più tabelle di grandi dimensioni. Durante l'aggiornamento 2-3 tabelle alla volta devono essere bloccate in modalità ESCLUSIVA.PostgreSQL ottiene e rilascia BLOCCO all'interno della funzione memorizzata

Poiché non tutti i tavoli devono essere bloccati allo stesso tempo, idealmente vorrei BLOCCARE solo quei tavoli che sto aggiornando in quel momento, e quindi rimuovere il lucchetto una volta fatto.

Es.

-- Lock first pair of tables 
LOCK TABLE tbl1_a IN EXCLUSIVE MODE; 
LOCK TABLE tbl1_b IN EXCLUSIVE MODE; 

-- Perform the update on tbl1_a and tbl1_b 

-- Release the locks on tbl1_a and tbl1_b 
-- HOW??? 

-- Proceed to the next pair of tables 
LOCK TABLE tbl2_a IN EXCLUSIVE MODE; 
LOCK TABLE tbl2_b IN EXCLUSIVE MODE; 

Sfortunatamente, non esiste l'equivalente dell'istruzione UNLOCK in plpgsql. Il modo normale per rimuovere LOCK consiste nel COMMITARE la transazione, ma ciò non è possibile all'interno di una funzione.

C'è qualche soluzione per questo? Un modo per rilasciare esplicitamente il blocco prima che la funzione venga eseguita? O eseguire una sorta di sotto-transazione (magari eseguendo ogni aggiornamento in una funzione separata)?

UPDATE

ho accettato che non esiste una soluzione. Scriverò ogni aggiornamento in una funzione separata e coordinerò dall'esterno del db. Grazie a tutti.

risposta

5

C'è in nessun modo. Le funzioni di Postgres sono atomiche (sempre all'interno di una transazione) e i blocchi vengono rilasciati alla fine di una transazione. E non ci sono ancora transazioni autonome.

Potrebbe essere possibile aggirare questo problema con advisory locks. Ma quelli non sono la stessa cosa Tutte le transazioni in competizione devono giocare insieme. L'accesso simultaneo che non è a conoscenza dei blocchi di avviso rovinerà la festa.

esempio Codice in dba.SE:

Oppure si potrebbe ottenere da qualche parte con "barare" operazioni autonome con dblink:

Oppure rivalutare il problema e suddividerlo in un paio di transazioni separate.

1

Non possibile. Dalla documentazione: Una volta acquisito, un blocco viene normalmente trattenuto fino alla fine della transazione. Ma se viene acquisito un blocco dopo aver stabilito un punto di salvataggio, il blocco viene rilasciato immediatamente se il punto di salvataggio viene riportato a. Questo è coerente con il principio che ROLLBACK annulla tutti gli effetti dei comandi dal punto di salvataggio. Lo stesso vale per i blocchi acquisiti all'interno di un blocco di eccezioni PL/pgSQL: un errore di fuga dal blocco rilascia i blocchi acquisiti al suo interno.

http://www.postgresql.org/docs/9.3/static/explicit-locking.html