2017-11-22 7 views
0

Ich entwickle ein Projekt mit WebAPI und Entity Framework 6.Wie ändert man eine parallele Datenbank sequentiell?

Es gibt einen Controller mit einer Methode, die der Datenbank einen neuen Entity Task hinzufügt. Vor der Add-Task wurde ein eindeutiger Name für sie berechnet. Ein Teil des Namens basiert auf den bereits gespeicherten Aufgaben in der Datenbank. Wenn Sie zwei parallele Anfragen stellen, können Sie die gleichen Namen generieren, dieses Problem wird durch Sperren gelöst.

Wie kann ich die Erzeugung identischer Namen verhindern, wenn zwei WebAPI-Server mit einer Verbindung zur selben Datenbank ausgeführt werden?

Ist es möglich, den Algorithmus zum Hinzufügen von Task zu einer sequenziellen Warteschlange auf Datenbankebene hinzuzufügen?

Vereinfachte Code:

[HttpPost] 
    [Route("add")] 
    public IHttpActionResult AddTask() 
    { 
     using (var db = CreateDbContext()) 
     { 
      Task task = new Task(); 

      lock (lockAdd) 
      { 
       DateTime dateTime = DateTime.UtcNow; 

       string preName = dateTime.ToString("yyMMdd-HHmm-"); 

       var query = db.Tasks.Where(t => t.Name.StartsWith(preName)).Select(t => t.Name); 

       List<string> tasksNames = query.ToList(); 

       task.Name = preName + (tasksNames.Count + 1).ToString("D4"); 

       db.Tasks.Add(task); 
       db.SaveChanges(); 
      } 

      return Ok(); 
     } 
    } 

Сolumn "Name" kann nicht eindeutig gemacht werden. Aufgaben wurden nie gelöscht. Zähler muss für jedes neue Datum (neue Minute) von 1 ausgehen.

+0

Der einfachste Weg wäre wahrscheinlich, die Logik in die Datenbank einzufügen und den Wert von dort zurückzugeben (vielleicht ein Insert-Trigger). So wird es immer richtig gehandhabt. Andernfalls müssen Sie einen eindeutigen Index haben und Ausnahmen behandeln, wenn derselbe Name eingefügt wird. –

Antwort

1

Sie sollten SEQUENCE zum Generieren von Daten auf Datenbankseite verwenden. Docs here. In diesem Fall wird die Eindeutigkeit von der Datenbank garantiert. Oder verwenden Sie Guid (UUID) - es bietet eindeutige Schlüssel. Docs here In diesem Fall Einzigartigkeit guarant von Idee von UUIDs

+0

Zähler muss für jedes neue Datum (neue Minute) von 1 beginnen –

0

Zusätzlich oben auf die Antwort, können Sie auch die Guid in C# erzeugen: https://msdn.microsoft.com/en-us/library/system.guid.newguid%28v=vs.110%29.aspx?f=255&MSPPError=-2147217396

Die Einzigartigkeit als GUID garantiert sowohl Zeit des Servers enthält und die MAC-Adresse des Servers. Es gibt auch einige kürzere Lösungen, wie zum Beispiel einen 64-Bit-UUID-Generator wie Snowflake. Für ein # port Beispiel C, siehe: https://github.com/mschuler/UniqueIdGenerator oder https://github.com/ccollie/snowflake-net/blob/master/Snowflake/IdWorker.cs

(Hinweis: Wenn Sie einen Singleton Snowflake Generator verwenden, müssen Sie nur eine Sperre auf dem ID-Generator, da die Einzigartigkeit durch einen Inkrementalzähler innerhalb derselben Millisekunde garantiert für bis zu 2^12 IDs/ms/server. Die zweite Quelle enthält dafür bereits eine Sperre.

+0

Zähler muss für jedes neue Datum (neue Minute) von 1 beginnen. –

+0

In diesem Fall, was Sie wirklich brauchen, ist keine Anwendungssperre, sondern eine Transaktion mit einer serialisierbaren Schreibsperre: https://www.postgresql.org/docs/9.1/static/transaction-iso.html –

Verwandte Themen