كيف يمكنني الحصول على معاملات خادم SQL لاستخدام أقفال مستوى السجل؟

StackOverflow https://stackoverflow.com/questions/2646439

سؤال

لدينا تطبيق تم كتابته في الأصل كتطبيق لسطح المكتب ، منذ عدة سنوات. يبدأ معاملة كلما قمت بفتح شاشة تحرير ، وترتبط إذا قمت بالنقر فوق "موافق" ، أو تراجع إذا قمت بالنقر فوق "إلغاء". لقد عمل هذا بشكل جيد لتطبيق سطح المكتب ، لكننا نحاول الآن الانتقال إلى خادم ADO.NET و SQL ، والمعاملات طويلة الأمد مشكلة.

لقد وجدت أنه سيكون لدينا مشكلة عندما يحاول العديد من المستخدمين تحرير (مجموعات فرعية مختلفة من) نفس الجدول في نفس الوقت. في قاعدة البيانات القديمة الخاصة بنا ، ستحصل معاملة كل مستخدم على أقفال على مستوى السجل لكل سجل قاموا بتعديله أثناء معاملتهم ؛ نظرًا لأن المستخدمين المختلفين كانوا يقومون بتحرير سجلات مختلفة ، فإن الجميع يحصلون على أقفالهم الخاصة وكل شيء يعمل. ولكن في SQL Server ، بمجرد قيام أحد المستخدمين بتحرير سجل داخل معاملة ، يبدو أن SQL Server يحصل على قفل على جدول كامل. عندما يحاول المستخدم الثاني تحرير سجل مختلف في نفس الجدول ، فإن تطبيق المستخدم الثاني يحبس ببساطة ، لأن SQLConnection يحظر حتى يرتكب المستخدم الأول أو يراجع.

أنا أدرك أن المعاملات طويلة الأمد سيئة ، وأنا أعلم أن أفضل سيكون الحل هو تغيير هذه الشاشات بحيث لم تعد تبقي المعاملات مفتوحة لفترة طويلة. ولكن نظرًا لأن هذا يعني بعض التغييرات الغازية والمحفوفة بالمخاطر ، أريد أيضًا البحث عما إذا كانت هناك طريقة للحصول على هذا الرمز وتشغيله ، فقط حتى أعرف ما هي خياراتي.

كيف يمكنني الحصول على معاملتين مختلفتين للمستخدمين في SQL Server لقفل السجلات الفردية بدلاً من الجدول بأكمله؟

إليك تطبيق وحدة تحكم سريع ودني يوضح المشكلة. لقد قمت بإنشاء قاعدة بيانات تسمى "Test1" ، مع جدول واحد يسمى "القيم" التي تحتوي فقط على أعمدة المعرف (int) وقيمة (NVARCHAR). إذا قمت بتشغيل التطبيق ، فإنه يطلب تعديل معرف ، ويبدأ معاملة ، ويعدل هذا السجل ، ثم يترك المعاملة مفتوحة حتى تضغط على Enter. اريد ان اكون قادرا على

  1. ابدأ البرنامج وأخبره بتحديث المعرف 1 ؛
  2. دعها تحصل على معاملتها وتعديل السجل ؛
  3. ابدأ نسخة ثانية من البرنامج وأخبرها بتحديث المعرف 2 ؛
  4. اجعلها قادرة على التحديث (والالتزام) في حين أن معاملة التطبيق الأول لا تزال مفتوحة.

حاليًا يتجمد في الخطوة 4 ، حتى أعود إلى النسخة الأولى من التطبيق وأغلقه أو اضغط على Enter بحيث يرتكب. Call to command.executenonquery كتل حتى يتم إغلاق الاتصال الأول.

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();
    }
}

إليك بعض الأشياء التي جربتها بالفعل ، دون تغيير في السلوك:

  • تغيير مستوى عزل المعاملة إلى "قراءة غير ملتزم"
  • تحديد "مع (Rowlock)" في بيان التحديث
هل كانت مفيدة؟

المحلول

مجرد التحقق ، ولكن هل لديك مفتاح أساسي أو فهرس فريد في عمود المعرف؟

نصائح أخرى

ابحث في قفل متفائل مقابل متشائم.

تحرير: المقالة السابقة مرتبطة بـ Classic Ado ... آسف.

http://msdn.microsoft.com/en-us/library/cs6hb8k4(vs.71).aspx

ربما تم إنشاء الفهرس باستخدام أقفال صف تم تعيينها على "OFF".
"مع (Rowlock)" في الاستعلام لن يكون له أي تأثير في هذه الحالة.

يمكنك إعادة تشغيلها مع تغيير فهرس, ، على سبيل المثال:

ALTER INDEX [PK_Values] ON [Values] SET (ALLOW_ROW_LOCKS = ON)
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top