2011-01-18 15 views
5

onun sistemi için özel bir müşteri ihtiyaç olduğu harf ve sayı birleştiren bir özel otomatik artış anahtarıdır.Okuma-yazma-yazma işlemi için kilit nasıl kurulur? Aşağıdaki tablo</p> <p><img src="https://i.stack.imgur.com/7QLHk.png" alt="Key(KeyId int, Sequence varchar(14))"></p> <p>sıra değerini göz önünde

Dizinin sonraki değerini döndürmesi gereken GetNextSequence() adında bir işlev yaptık. Tabloya dizisi değerini yaz dizisi değerini Ayrıştırma SELECT Sequence FROM [Key] WHERE KeyId = @Id

  • ve sonraki değerini
  • belirlemek:

    1. KeyID kullanarak dizisi değerini oku izleyin olarak okuma ve diziyi güncellenmesi için adım gider UPDATE [Key] SET Sequence = @Sequence WHERE KeyId = @Id

      var transaction = connection.BeginTransaction(IsolationLevel.RepeatableRead); 
      var currentSequenceValue = SqlUtils.ExecuteScalar(connection, transaction, "SELECT Sequence FROM [Key] WHERE KeyId = @Id", new SqlParameter("@Id", keyId)); 
      var updatedSequenceValue = ParseSequence(currentSequenceValue); 
      SqlUtils.ExecuteScalar(connection, transaction, "UPDATE [Key] SET Sequence = @Sequence WHERE KeyId = @Id", new SqlParameter("@Id", keyId), new SqlParameter("@Sequence", updatedSequenceValue)); 
      transaction.Commit(); 
      return updatedSequenceValue; 
      
      : Burada

  • (netlik için basitleştirilmiş) C# kodu

    Bizim sorunumuz aynı diziyi erişebilmesi iki farklı sunucularda ikamet ve biz başka bir işlem kilit kaynaklardaki deadlocked ve kilitlenme kurbanı olarak seçildi çıkmaza

    İşlem (Process ID X) elde sonunda. İşlemi tekrar çalıştırın. C# '

    , ben tablo ipucu ROWLOCK ve HOLDLOCK kullanarak bir işlem izolasyon IsolationLevel.RepeatableRead veya IsolationLevel.Serializable veya SQL gibi farklı kilit kombinasyonunu kurmaya çalıştı, ancak başarılı olamadı.

    Her sunucunun bir diziyi atomik olarak okuyabilmesi, değiştirebilmesini ve güncelleştirebilmesini istiyorum. Bu durum için bir kilit oluşturmanın uygun yolu nedir? Bir işlemin süresi boyunca özel bir satır düzeyinde kilit kullanmayı (ROWLOCK, XLOCK, HOLDLOCK) kullanmanızı öneririm

    +0

    Bu sorun gibi geliyor: http://www.codinghorror.com/blog/2008/08/deadlocked.html – BrokenGlass

    cevap

    1

    İpucu vb. Kullanımınız yeterli değil.

    BEGIN TRAN 
        SELECT Sequence FROM [Key] WITH (ROWLOCK, XLOCK, HOLDLOCK) WHERE KeyId = @Id 
    
        Parse the sequence value and determine the next value 
    
        UPDATE [Key] SET Sequence = @Sequence WHERE KeyId = @Id 
    COMMIT 
    

    rağmen, en azından tek bir işlem ile

    UPDATE [Key] WITH (ROWLOCK, XLOCK, HOLDLOCK) 
        SET Sequence = dbo.scalarudf(...) 
        WHERE KeyId = @Id 
    

    Edit kapsamının daraltılması bakardık: Eğer SERIALIZABLE kullanırsanız HOLDLOCK gerekmez. Ve "RepeatableRead", aralıkların nasıl kilitlendiğinden dolayı yeterli olmayabilir.

    +0

    Oh, "Ayrıştırma dizisi" C# yapılmaması gerektiğini belirtmeliyim SQL Server'da. –

    +1

    @ Pierre-Alain Vigeant: hala ipuçlarına ve işlemlere ihtiyacınız var. C# bir CLR fraksiyonuna veya SQL'e taşıyabilir misin? – gbn

    +0

    'ROWLOCK, XLOCK, HOLDLOCK' ile çalışıyor gibi görünüyor, ancak yarın yapacağım daha fazla test gerekiyor. –

    2

    Sorun, okuma için varsayılan kilitlerin elde edilmesinin, yarış koşullarından kaçınmamasıdır, çünkü aynı kayıtta çoklu okuma kilitleri elde edilebilir. Durum A ise, A işleminin X satırında bir Okuma kilidi almasıdır. İşlem B daha sonra A "istemci tarafı" üzerinde çalışırken (sunucu programı dahilinde) bir okuyucu kilidi edinir. A, B tarafındaki istemci tarafında çalıştığı sırada, Yazma kilidine yükseltme yapılmasını ister, bu noktada, B oku okuma kilidi serbest bırakılıncaya kadar beklemesi söylenir. B daha sonra bir Yazma kilidini ister ve A, Oku'yı yayınlayana kadar beklemek için tols olur. İkisi de şimdi diğerlerini bekliyor, böylece daha özel Yazma kilidini elde edebilirler.

    Çözüm özel bir kilittir; XLOCK ipucunu kullanarak bunu belirtebilirsiniz.Özel bir kilit temelde bir okuma için edinilen Yazma düzeyindeki bir kilittir ve okuduğunuz bir şeyi yazmayı beklediğiniz bu durumda kullanılır. Açıklamalarda belirtildiği gibi, özel bir kilit yalnızca ifade açık bir işlem kapsamında yürütülürse korunur, bu nedenle değeri nasıl okuyacağınızı belirleyen "okuma birimi" sırasında bir tane ayarladığınızdan emin olun. o ve daha sonra güncelleştirmek.

    Çok sayıda benzer diziyi bir kerede güncelleştirmediyseniz, bunu satır düzeyinde (ROWLOCK) kullanırım; Bir sayfa veya tablo düzeyinde özel bir kilit elde etmek, EVERYBYY'yi yalnızca işlem başına bir satırda çalışıyorsanız ihtiyacınız olmayan verileri bekletir. Bir yan not

    +0

    XLOCK, yalnızca açık bir işlem yapılmadığı sürece geçerli deyim için devam eder. Bu kendi başına yeterli değildir. Dolayısıyla, SELECT için kullanılırsa, UPDATE'de hâlâ bir kilitlenme olabilir. – gbn

    +0

    Açık bir işlem varsayıyordum; GetNextSequence() işlevi, söz konusu sözcükten atomik bir "iş birimi" dir. – KeithS

    +0

    Doğru, ancak özel kilitin kalıcılığı konusunda daha net olmalı – gbn

    İlgili konular