Domanda

Abbiamo un'applicazione che è stato originariamente scritto come un'applicazione desktop, ecco questi molti anni fa. Si avvia una transazione ogni volta che si apre una schermata di modifica, e si impegna, se si fa clic su OK, o il rollback se si sceglie Annulla. Questo ha funzionato bene per un'applicazione desktop, ma ora stiamo cercando di trasferirsi in ADO.NET e SQL Server, e le transazioni a lungo in esecuzione sono problematici.

ho scoperto che avremo un problema quando più utenti stanno tutti cercando di modificare (diversi sottoinsiemi di) della stessa tabella allo stesso tempo. Nel nostro vecchio database, transazioni di ogni utente avrebbe acquisire blocchi a livello di record per ogni record hanno modificato durante la loro operazione; dal momento che diversi utenti sono stati modificando diversi record, ognuno ottiene il loro serrature e tutto funziona proprio. Ma in SQL Server, non appena un utente modifica un record all'interno di una transazione, SQL Server sembra ottenere un blocco sul intera tabella. quando un secondo tentativi all'utente di modificare un altro record nella stessa tabella , applicazione del secondo utente blocca semplicemente in su, perché i blocchi SqlConnection fino al primo utente sia commit o il rollback.

Sono consapevole del fatto che le operazioni a lungo in esecuzione sono male, e so che il migliore soluzione sarebbe quella di modificare questi schermi in modo che essi continuano a non più transazioni aperte per lungo tempo. Ma poiché ciò significherebbe alcune modifiche invasive e rischiose, voglio anche ricerca se c'è un modo per ottenere questo codice attivo e funzionante così com'è, basta quindi so quali sono le mie opzioni.

Come posso ottenere le transazioni due diversi utenti in SQL Server per bloccare singoli record anziché l'intero tavolo?

Ecco una console app quick-and-dirty che illustra il problema. Ho creato un database chiamato "test1", con una tabella denominata "Valori" che ha appena ID (int) e Valore colonne (nvarchar). Se si esegue l'applicazione, si chiede un ID di modificare, avvia una transazione, modifica il record, e poi lascia allo scoperto di transazione finché non si preme INVIO. Voglio essere in grado di

  1. avviare il programma e dirgli di aggiornamento ID 1;
  2. lasciarlo arrivare la sua operazione e modificare il record;
  3. avviare una seconda copia del programma e dirgli di aggiornamento ID 2;
  4. ce l'ha in grado di aggiornare (e commit), mentre transazione del primo app è ancora aperto.

Al momento si blocca al punto 4, fino a quando torno la prima copia della app e chiuderlo o premere Invio in modo che si impegna. La chiamata a blocchi command.ExecuteNonQuery fino alla prima connessione è chiusa.

public static void Main()
{
    Console.Write("ID to update: ");
    var id = int.Parse(Console.ReadLine());
    Console.WriteLine("Starting transaction");
    using (var scope = new TransactionScope())
    using (var connection = new SqlConnection(@"Data Source=localhost\sqlexpress;Initial Catalog=test1;Integrated Security=True"))
    {
        connection.Open();
        var command = connection.CreateCommand();
        command.CommandText = "UPDATE [Values] SET Value = 'Value' WHERE ID = " + id;
        Console.WriteLine("Updating record");
        command.ExecuteNonQuery();
        Console.Write("Press ENTER to end transaction: ");
        Console.ReadLine();
        scope.Complete();
    }
}

Qui ci sono alcune cose che ho già provato, senza alcun cambiamento nel comportamento:

  • Modifica del livello di isolamento delle transazioni a "leggere non impegnati"
  • Specificare un "CON (ROWLOCK)" a UPDATE
È stato utile?

Soluzione

solo controllando, ma non si dispone di una chiave primaria o indice univoco nella colonna ID?

Altri suggerimenti

Se vuoi in ottimistico contro il blocco pessimistico.

Modifica: Articolo precedente legato al rumore classico ... mi dispiace.

http://msdn.microsoft.com/ it-it / library / cs6hb8k4 (VS.71) aspx

Probabilmente l'indice è stato creato con blocchi di riga impostato su "off".
"CON (ROWLOCK)" in una query non avrebbe alcun effetto in questo caso.

È possibile riaccenderli con ALTER INDEX , ad esempio, :

ALTER INDEX [PK_Values] ON [Values] SET (ALLOW_ROW_LOCKS = ON)
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top