2011-01-01 11 views
0

sah ich einen Code, in dem sie die Datenzugriffsschicht wie dieses:net C# lock-Anweisung in der Datenzugriffsschicht

public class CustomerDA{ 

    private static readonly object _sync = new object(); 
    private static readonly CustomerDA _mutex = new CustomerDA(); 

    private CustomerDA(){ 
    } 

    public CustomerDA GetInstance(){  

     lock(_sync){  
      return _mutex;   
     }  
    } 

    public DataSet GetCustomers(){ 
     //database SELECT 
     //return a DataSet 
    } 

    public int UpdateCustomer(some parameters){ 

     //update some user 
    } 

} 


public class CustomerBO{ 

    public DataSet GetCustomers(){ 

     //some bussiness logic 
     return CustomerDA.GetInstance().GetCustomers(); 
    } 
} 

ich es verwenden, aber anfangen zu denken ... „und was ist, wenn bauen musste eine Facebook-ähnliche Anwendung, wo es Hunderttausende von gleichzeitigen Benutzern gibt? würde ich jeden Benutzer daran hindern, seine Sachen zu machen, bis der vorherige Benutzer seine Datenbank-Sachen beendet? und für die Update-Methode, ist es nützlich, THREADS in der App zu sperren, wenn Datenbank Engines verwalten bereits Parallelität auf Datenbankserverebene? "

Dann begann ich über das Verschieben der Sperre zu den GetCustomers und UpdateCustomer Methoden nachzudenken, aber denken Sie noch einmal: "Ist es überhaupt nützlich?"

bearbeiten am Januar 03:

Sie alles in Ordnung sind, verpasste ich die "statische" Schlüsselwort in der "GetInstance" -Methode.

Anther Sache: Ich war in der Idee, dass kein Thread auf die Variable _mutex zugreifen konnte, wenn ein anderer Thread in der gleichen Datenzugriffsklasse arbeiten würde. Ich meine, ich dachte, seit die _mutex-Variable von innerhalb der Lock-Anweisung zurückgegeben wird, konnte kein Thread auf die _mutex zugreifen, bis die ";" wurde im folgenden Satz erreicht:

return CustomerDA.GetInstance().GetCustomer();

Nach einiger Verfolgung tun, merke ich, ich die falsche Annahme machte. Könnten Sie bitte bestätigen, dass ich die falsche Annahme gemacht habe?

So ... Kann ich sicher sagen, dass meine Datenzugriffsebene keine Sperranweisung benötigt (selbst bei INSERT, UPDATE, DELETE) und dass es keine Rolle spielt, ob Methoden in meinem DataAccess statische oder Instanzmethoden sind?

Thanks again ... Ihre Kommentare sind mir so nützlich

+2

Wo immer Sie diesen Code gesehen haben, schauen Sie nie wieder dorthin. Das ist einfach schlechter Code. Ignoriere es. –

+1

Ich glaube, derjenige, der den Code geschrieben hat, sollte einen Singleton von CustomerDA haben. Die Sperre bei GetInstance() ist nicht wirklich notwendig, da _mutex schreibgeschützt ist. Sie werden nicht blockiert, wenn Sie die SQL-Anweisungen ausführen, da es bei GetCustomer() und UpdateCustomer() keine Sperre gibt. –

Antwort

1

Das Schloss in diesem Code völlig sinnlos ist. Es sperrt den Code, der einen Wert zurückgibt, der sich nie ändert, daher gibt es keinen Grund, eine Sperre dort zu haben. Der Zweck der Sperre im Code besteht darin, das Objekt zu einem Singleton zu machen, aber da es keine faule Initialisierung verwendet, wird die Sperre überhaupt nicht benötigt.

Die Datenzugriffsschicht als Singleton zu erstellen, ist eine sehr schlechte Idee, dh immer nur ein Thread kann auf die Datenbank zugreifen. Es bedeutet auch, dass die Methoden in der Klasse Sperren verwenden müssen, um sicherzustellen, dass immer nur ein Thread auf die Datenbank zugreift oder der Code nicht ordnungsgemäß funktioniert.

Stattdessen sollte jeder Thread eine eigene Instanz der Datenzugriffsebene mit einer eigenen Verbindung zur Datenbank erhalten. Auf diese Weise kümmert sich die Datenbank um die Gleichzeitigkeitsprobleme, und die Theads müssen überhaupt nicht sperren.

+0

Ich bin mir nicht sicher, ob ich damit einverstanden bin. Es gibt eine Reihe von Annahmen. Ein Singleton für eine DAL bedeutet nicht, dass es keinen Verbindungspool verwenden kann, um gleichzeitige Verbindungen mit mehreren Threads zuzulassen. Nicht zu vergessen, der Code sieht nicht korrekt aus. GetInstance() sollte statisch sein, ist es aber nicht. Entweder dachten sie, die Sperre würde nur einem Benutzer den Zugriff auf die Datenbank ermöglichen, oder es war eine falsche Implementierung der Double-Checked-Sperre, um sicherzustellen, dass nur eine Instanz erstellt wurde. –

+0

@Andrew Finnell: Ja, eine Singleton-Klasse mit einem Verbindungspool würde auch funktionieren, aber aus der Beschreibung in der Frage klingt es nicht so, als ob es derzeit so etwas gäbe. – Guffa

0

Stellen Sie Ihr Schloss dort ein, wo es benötigt wird, also wo gleichzeitige Zugriffe stattfinden. Fügen Sie nur so viel Code in den Lock/Critical Section ein, wie Sie wirklich benötigen.

Das GetInstance sollte nicht statisch sein?

Der folgende Pseudocode erläutert, wie GetInstance arbeitet:

  1. LOCK
  2. rval = _mutex
  3. UNLOCK
  4. Return rval

_mutex nur lesbar ist, bezieht sich auf eine nicht- Null-Objekt, so dass es nicht geändert werden kann, warum sperren?

Wenn Ihre Datenbank Gleichzeitigkeitsverwaltung bietet, aber in Ihrem Programm erstellen Sie zwei Threads schreiben die gleichen Daten in der gleichen Zeit in Ihrer eigenen Domäne, während Sie auf die Daten warten, Wie könnte Ihre Datenbank helfen?

+0

Was meinst du mit dem letzten Teil deiner Antwort (wie könnte die Datenbank helfen, wenn es zwei Threads gibt, die dieselben Daten zur gleichen Zeit schreiben)? Also, ist es eine gute Idee, wenn ich das Schloss auf die Methodenebene nehme? so etwas wie: "public int UpdateCustomer() {lock {// irgendeinen Code hier}}" –

+0

Denke nicht so: "Ich verschließe die Dinge immer hier". Wenn Sie beispielsweise nur eine Verbindung zur Datenbank verwenden möchten, müssen Sie nur die Anweisungen sperren, die diese Verbindung verwenden, und keine anderen. Versenken Sie die Sperren immer so tief wie möglich und sperren Sie keine Anweisungen, die gleichzeitig ausgeführt werden können. "public int UpdateCustomer() {/ * lokale Berechnungen */.. lock {/ * Verwendung von globalen Variablen, Aufrufen nicht threadsicherer Funktionen von globalen Objekten usw. * /}/* more local computing * //}}" – ch0kee

+0

Also nochmal generell: enge Schlösser so viel wie möglich! Wenn Sie denken, dass Sie nicht tiefer gehen können, fragen Sie sich, welche Anweisungen diesen Funktionsaufruf stören würden. dann gehe in diese Funktion und wiederhole es. Sie werden einen Punkt erreichen (wie file.write (a) und schreiben ist in einer Bibliothek), wenn Sie nicht mehr eingrenzen können. Sie sehen den Punkt? Dies ist eine gute Taktik, um einige Deadlocks zu vermeiden, da Sie sofort gesperrte Objekte freigeben, so dass niemand auf eine unnötige Sperre warten muss). Diese 3 Sache muss streng aufeinander folgen: 1) LOCK 2) GET_DATA_FROM_LOCKED 3) UNLOCK_IMMEDIATELY – ch0kee

Verwandte Themen