none
Select + Update concorrenti RRS feed

  • Domanda

  • Chiedo delucidazioni su questo tipo di scenario.
    Ho una funzione in Vb.net che mi restituisce un numero. La funzione in particolare effettua prima una select su una tabella quindi update sulla stessa tabella (in pratica fa numero+1). E' il classico esempio di un contatore.
    Se 1000 utenti accedono alla stessa funziona contemporaneamente ho la certezza di avere per ogni utente un numero univoco? Le istruzioni in pratica anche se eseguite nello stesso momento vengono come "accodate" per cui ho sempre una sequenza select/update, select/update ecc ecc?
    Chi può illuminarmi?
    Raluto e saluto
    mercoledì 10 febbraio 2010 13:05

Risposte

  • Ciao Andre,

    nulla vieta a due o più utenti ad eseguire la stessa funzione nello stesso tempo, quindi  due o più utenti possono ricevere lo stesso numero di contatore, ovvero non hai nessuna certezza.

    per blindare il tutto si potrebbe mettere un blocco sulla tabella in modo che tra la lettura e la scrittura nessun altro possa andare a leggere il nuovo contatore.
    In t-sql si potrebbe fare così:
    DECLARE @Contatore Int
    
    BEGIN TRANSACTION
    
    -- Leggo il contatore
    SELECT @Contatore = MAX(Contatore)
    FROM   dbo.Tabella
    WITH (TABLOCKX)
    
    -- Scrivo il contatore
    UPDATE dbo.Tabella
       SET Contatore = IsNull(@Contatore,0)+1
    WHERE  .........
    
    COMMIT TRANSACTION
    Apre una transazione, legge il contatore e blocca la tabella, poi scrive il contatore e chiude la transazione sbloccando la tabella.
    Per maggiori info vedi:
    ----
    Hint di tabella (Transact-SQL)
    http://msdn.microsoft.com/it-it/library/ms187373.aspx
    ----

    Ciao
    Giorgio Rancati
    domenica 14 febbraio 2010 10:47
    Moderatore

Tutte le risposte

  • Ciao Andre,

    nulla vieta a due o più utenti ad eseguire la stessa funzione nello stesso tempo, quindi  due o più utenti possono ricevere lo stesso numero di contatore, ovvero non hai nessuna certezza.

    per blindare il tutto si potrebbe mettere un blocco sulla tabella in modo che tra la lettura e la scrittura nessun altro possa andare a leggere il nuovo contatore.
    In t-sql si potrebbe fare così:
    DECLARE @Contatore Int
    
    BEGIN TRANSACTION
    
    -- Leggo il contatore
    SELECT @Contatore = MAX(Contatore)
    FROM   dbo.Tabella
    WITH (TABLOCKX)
    
    -- Scrivo il contatore
    UPDATE dbo.Tabella
       SET Contatore = IsNull(@Contatore,0)+1
    WHERE  .........
    
    COMMIT TRANSACTION
    Apre una transazione, legge il contatore e blocca la tabella, poi scrive il contatore e chiude la transazione sbloccando la tabella.
    Per maggiori info vedi:
    ----
    Hint di tabella (Transact-SQL)
    http://msdn.microsoft.com/it-it/library/ms187373.aspx
    ----

    Ciao
    Giorgio Rancati
    domenica 14 febbraio 2010 10:47
    Moderatore
  • Ciao Giorgio,
    grazie della tua risposta. La tua soluzione è molto chiara e documentata. Ho letto varie cose su msdn ma a questo punto mi sorge una domanda, direi LA DOMANDA. Lavorando in VB.net dove ho il dato dissociato dalla mia base dati mi consigli il lock oppure la concorrenza ottimistica? Cioè meglio bloccare per pochissimi istanti questa tabella dei contatori oppure far gestire anche questa tabella alla concorrenza ottimistica? Certo che non è bello incontrare un conflitto in fase di ottenimento di un ID o Numero documento...è per questo motivo che sposerei il lock. Tu come la vedi?
    Ringrazio nuovamente e saluto
    Andrea

    mercoledì 17 febbraio 2010 11:38
  • Ciao Andrea,

    io non avrei dubbi, bloccherei la tabella il tempo necessario per leggere il nuovo protocollo e scriverlo, però i due step, lettura e scrittura, li farei girare in un solo batch da eseguire lato server. Quindi non una funzione Vb che legge il protocollo e una seconda che lo scrive, ma tutte e due le operazioni in un solo batch.

    Io lavoro con i progetti ADP di Access che usano di default la concorrenza ottimistica, però quando devo inserire una nuova Fattura, faccio assegnare il numero di protocollo direttamente da un trigger (con access è la via più semplice) bloccando la tabella il tempo necessario per leggere il protocollo e scriverlo, ovviamente l'intera operazione viene eseguita lato server.

    Ciao
    Giorgio Rancati
    mercoledì 17 febbraio 2010 18:14
    Moderatore