2010-09-22 15 views
8

Voglio bloccare un record e quindi nessuno può apportare modifiche a quel record. Quando rilascio il blocco, le persone possono cambiare il record.Come eseguire un blocco riga?

Nel frattempo che un record è bloccato, voglio mostrare all'utente un avviso che il record è bloccato e che le modifiche non sono consentite.

Come posso fare questo?

Ho provato tutti i livelli di IsolationLevel, ma nessuno di loro ha il comportamento che voglio. Alcuni livelli di isolamento attendono fino al rilascio del blocco e quindi apportano una modifica. Non voglio questo, perché l'aggiornamento non è consentito al momento un record è bloccato.

Cosa posso fare per bloccare un record e negare tutte le modifiche?

Io uso di SQL Server 2008

+0

Dipende dal database. Quale? – pascal

+0

SQL Server 2008 – Martijn

risposta

0

Vedere questo duplicate question su SO.

In sostanza è:

begin tran 

select * from [table] with(holdlock,rowlock) where id = @id 

--Here goes your stuff 

commit tran 

Archivio

Qualcosa di simile forse?

update t 
set t.IsLocked = 1 
from [table] t 
where t.id = @id 

qualche parte nel trigger di aggiornamento:

if exists (
select top 1 1 
from deleted d 
join inserted i on i.id = d.id 
where d.IsLocked = 1 and i.RowVersion <> d.RowVersion) 
begin 
print 'Row is locked' 
rollback tran 
end 
+0

Ho provato questo, ma sono ancora in grado di selezionare i dati e quando eseguo un aggiornamento, l'istruzione attende che il blocco venga rilasciato e quindi esegue l'aggiornamento. Questo non è quello che voglio. Voglio avvisare l'utente se un record è bloccato. – Martijn

1

SQL Server ha note di bloccaggio, ma questi sono limitati alla portata di una query.

Se la decisione di bloccare il record viene eseguita in un'applicazione, è possibile utilizzare gli stessi meccanismi del blocco ottimistico e negare qualsiasi modifica al record dall'applicazione.

Utilizzare un timestamp o un guid come blocco del record e negare l'accesso o le modifiche al record se viene fornito il codice di blocco errato. State attenti a sbloccare nuovamente i record o otterrete orfani

+1

Ho pensato a un simile approccio, ma cosa succede se l'applicazione si blocca? O se il server va giù. Come posso sbloccare il disco in una situazione del genere? – Martijn

+0

Non c'è un modo semplice, penso. Arrestare i blocchi registrando un datetime che è stato bloccato e utilizzare un trigger o un processo pianificato per pulire i blocchi che esistono troppo a lungo. Quello che stai facendo essenzialmente è il blocco pessimistico. vedere anche questo: http://stackoverflow.com/questions/386162/pessimistic-lock-in-t-sql – stombeur

9

Partendo dal presupposto che si tratta di server MS SQL, probabilmente si desidera UPDLOCK, eventualmente combinato con ROWLOCK (Table hints). Sto avendo difficoltà a trovare un articolo decente che descrive la teoria, ma qui è rapido esempio:

SELECT id From mytable WITH (ROWLOCK, UPDLOCK) WHERE id = 1 

Questa affermazione sarà posto un update lock sulla riga per tutta la durata della transazione (quindi è importante essere consapevoli di quando la transazione finirà). Poiché i blocchi di aggiornamento sono incompatible with exclusive locks (necessari per aggiornare i record), ciò impedirà a chiunque di aggiornare questo record fino al termine della transazione.

Si noti che altri processi che tentano di modificare questo record verranno bloccati fino al completamento della transazione, tuttavia continueranno con qualsiasi operazione di scrittura richiesta una volta che la transazione è terminata (a meno che non siano scaduti o eliminati come processi con deadlock). Se si desidera impedire ciò, gli altri processi devono utilizzare ulteriori suggerimenti per interrompere se viene rilevato un blocco incompatibile o saltare il record se è stato modificato.


Inoltre, Si consiglia di non utilizzare questo metodo per bloccare i record in attesa di input dell'utente. Se questa è la tua intenzione, allora dovresti aggiungere una sorta di colonna "in fase di modifica" al tuo tavolo.

Il server SQL meccanismi di bloccaggio sono veramente adatto solo per l'uso per preservare l'integrità dei dati/prevenzione deadlock - operazioni dovrebbero generalmente essere mantenuti più breve possibile e non dovrebbe certamente essere mantenuti in attesa di input dell'utente.

+0

Quando lo uso, la dichiarazione di aggiornamento attende finché il blocco non viene rilasciato e quindi esegue un aggiornamento. Non voglio questo comportamento. Non appena un record viene bloccato, l'utente deve vedere un messaggio. Facendolo in questo modo, non posso avvisare l'utente perché la dichiarazione di aggiornamento rimane in attesa fino al rilascio del blocco. Voglio che la dichiarazione di aggiornamento si interrompa e fornisca in qualche modo un errore/eccezione/avvertimento, così posso avvisare l'utente. – Martijn

+0

@Martijn - La seconda istruzione di aggiornamento deve essere eseguita con l'hint 'NOWAIT', che causerà il ritorno non appena viene rilevato un blocco piuttosto che attendere il timeout. – Justin

+0

Non dovrebbe leggere l'istruzione 'SELECT id From mytable WITH (ROWLOCK, UPDLOCK) WHERE id = 1'? – nash

0

Non si desidera attendere il rilascio del blocco e mostrare il messaggio non appena si incontra un lucchetto, se questo è il caso, si è provato a provare NOWAIT. Vedi Table Hints (Transact-SQL) e SQL Server 2008 Table Hints per maggiori dettagli. Per ottenere il vantaggio di NOWAIT devi bloccare i record sulle modifiche, google per ulteriori dettagli.

Problemi correlati