قفل المشكلات مع SQLite و Subsic عند استخدام المعاملات على مؤشر ترابط واحد

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

سؤال

أحصل على استثناءات قفل عند محاولة استخدام المعاملات مع SQLITE SQLITE. أنا أستخدم هذا من موضوع واحد ولا توجد عمليات أخرى تصل إلى ديسيبل ، لذلك لم أتوقع حقًا أي من هذه المشكلات.

إذا قمت بكتابة كود مثل هذا أدناه ، أحصل على استثناء في المكالمة الثانية لحفظ () داخل الحلقة - وبالتالي فإن المكالمة الثالثة لحفظ () على الجميع.

       using (TransactionScope ts = new TransactionScope())
       {
            using (SharedDbConnectionScope sharedConnectinScope = new SharedDbConnectionScope())
            { 
                SomeDALObject x = new SomeDALObject()
                x.Property1 = "blah";
                x.Property2 = "blah blah";
                x.Save();

                foreach (KeyValuePair<string, string> attribute in attributes)
                { 
                    AnotherDALObject y = new AnotherDALObject()
                    y.Property1 = attribute.Key
                    y.Property2 = attribute.Value

                    y.Save();  // this is where the exception is raised, on the 2nd time through this loop
                }
            }
       }

إذا كان لدي بيانات استخدام () على النحو الوارد أعلاه ، أو إذا كان لدي للتو using (TransactionScope ts = new TransactionScope()) ثم أحصل على ملف System.Data.SQLite.SQLiteException مع الرسالة

تم قفل ملف قاعدة البيانات

قاعدة البيانات مغلقة

تتبع المكدس هو:

   at System.Data.SQLite.SQLite3.Step(SQLiteStatement stmt)
   at System.Data.SQLite.SQLiteDataReader.NextResult()
   at System.Data.SQLite.SQLiteDataReader..ctor(SQLiteCommand cmd, CommandBehavior behave)
   at System.Data.SQLite.SQLiteCommand.ExecuteReader(CommandBehavior behavior)
   at System.Data.SQLite.SQLiteCommand.ExecuteNonQuery()
   at System.Data.SQLite.SQLiteTransaction..ctor(SQLiteConnection connection, Boolean deferredLock)
   at System.Data.SQLite.SQLiteConnection.BeginDbTransaction(IsolationLevel isolationLevel)
   at System.Data.SQLite.SQLiteConnection.BeginTransaction()
   at System.Data.SQLite.SQLiteEnlistment..ctor(SQLiteConnection cnn, Transaction scope)
   at System.Data.SQLite.SQLiteConnection.EnlistTransaction(Transaction transaction)
   at System.Data.SQLite.SQLiteConnection.Open()
   at SubSonic.SQLiteDataProvider.CreateConnection(String newConnectionString)
   at SubSonic.SQLiteDataProvider.CreateConnection()
   at SubSonic.SQLiteDataProvider.ExecuteScalar(QueryCommand qry)
   at SubSonic.DataService.ExecuteScalar(QueryCommand cmd)
   at SubSonic.ActiveRecord`1.Save(String userName)
   at SubSonic.ActiveRecord`1.Save()
   at (my line of code above).

إذا كان لديّ استخدام الإحصاءات المتداخلة في الاتجاه الآخر ، مع مشاركتها في الخارج ، أحصل على ملف TransactionException مع رسالة "العملية غير صالحة لحالة المعاملة." تتبع المكدس هو:

at System.Transactions.TransactionState.EnlistVolatile(InternalTransaction tx, IEnlistmentNotification enlistmentNotification, EnlistmentOptions enlistmentOptions, Transaction atomicTransaction)
   at System.Transactions.Transaction.EnlistVolatile(IEnlistmentNotification enlistmentNotification, EnlistmentOptions enlistmentOptions)
   at System.Data.SQLite.SQLiteEnlistment..ctor(SQLiteConnection cnn, Transaction scope)
   at System.Data.SQLite.SQLiteConnection.EnlistTransaction(Transaction transaction)
   at System.Data.SQLite.SQLiteConnection.Open()
   at SubSonic.SQLiteDataProvider.CreateConnection(String newConnectionString)
   at SubSonic.SQLiteDataProvider.CreateConnection()
   at SubSonic.SQLiteDataProvider.ExecuteScalar(QueryCommand qry)
   at SubSonic.DataService.ExecuteScalar(QueryCommand cmd)
   at SubSonic.ActiveRecord`1.Save(String userName)
   at SubSonic.ActiveRecord`1.Save()
   at (my line of code above)

والاستثناء الداخلي هو "مهلة المعاملات"

ليس لدي أي رمز مخصص في فصول DAL التي تم إنشاؤها ، أو أي شيء آخر ذكي يمكنني التفكير في أنه سيؤدي إلى ذلك.

أي شخص آخر واجه مشاكل في المعاملات مثل هذا أو هل يمكن لأي شخص أن يقترح من أين أبدأ البحث عن المشكلة؟

شكرًا!

تحديث: لاحظت ذكر الأشياء المتعلقة بالمعاملات في ملاحظات الإصدار للإصدارات 1.0.61-65 (على سبيل المثال هنا) ، لذلك ربما تحديث Subsong للعمل مع أحدث إصدار من مزود بيانات .NET سيحل بعض هذه المشكلات ...

هل كانت مفيدة؟

المحلول

عند القيام بمزود SQLite المنقح لـ Subsonic 2.x ، قمت بإنشاء مجموعة كاملة من اختبارات الوحدة بناءً على اختبارات SQLServer SQLServer الموجودة. (تم التحقق من هذه الاختبارات أيضًا مع الكود المنقح.) كانت الاختبارات الوحيدة التي فشلت هي الاختبارات المتعلقة بالمعاملات (ربما التصرفات الهجرة أيضًا). "ملف قاعدة البيانات مقفل" رسالة خطأ ، كما رأيت. تمت كتابة Subsonic بشكل أساسي لخادم SQL الذي لا يقوم بقفل مستوى الملف كما يفعل SQLite ، لذلك بعض الأشياء لا تعمل ؛ يجب إعادة كتابة ذلك للتعامل مع هذا بشكل أفضل.

لم أستخدم TransactionsCope كما لديك. أقوم بمعاملتي Subsic 2.2 مثل هذا ، وحتى الآن لا توجد مشاكل مع مزود SQLite. يمكنني التأكد من أنك بحاجة إلى استخدام المعاملات مع SQLite إذا كنت تتعامل مع صفوف متعددة أو أنها بطيئة حقًا.

public void DeleteStuff(List<Stuff> piaRemoves)
{
    QueryCommandCollection qcc = new QueryCommandCollection();

    foreach(Stuff item in piaRemoves)
    {
        Query qry1 = new Query(Stuff.Schema);
        qry1.QueryType = QueryType.Delete;
        qry1.AddWhere(Stuff.Columns.ItemID, item.ItemID);
        qry1.AddWhere(Stuff.Columns.ColumnID, item.ColumnID);
        qry1.AddWhere(Stuff.Columns.ParentID, item.ParentID);
        QueryCommand cmd = qry1.BuildDeleteCommand();
        qcc.Add(cmd);
    }
    DataService.ExecuteTransaction(qcc);
}

نصائح أخرى

انتهى بي الأمر باستخدام اقتراح بول وإعادة كتابة الكود الخاص بي إلى شيء مثل هذا:

    QueryCommandCollection qcc = new QueryCommandCollection();

    SomeDALObject x = new SomeDALObject()
    x.Property1 = "blah";
    x.Property2 = "blah blah";
    qcc.Add(x.GetSaveCommand());

    foreach (KeyValuePair<string, string> attribute in attributes)
    { 
        AnotherDALObject y = new AnotherDALObject()
        y.Property1 = attribute.Key
        y.Property2 = attribute.Value

        qcc.Add(y.GetSaveCommand());
    }

    DataService.ExecuteTransaction(qcc);

هذا في الواقع أفضل بكثير لأن جميع التحضير لضربات قاعدة البيانات يتم قبل فتح المعاملة ، وبالتالي فإن المعاملة ستكون مفتوحة لفترة أقل بكثير.

لن يعمل هذا بشكل جيد إذا كنت بحاجة إلى استعادة معرفات تم إنشاؤها تلقائيًا من أجل تشغيل إدراج لسجلات الأطفال ؛ ستحتاج إلى استخدام نهج مختلف لذلك.

ثم ضربت بعض مشكلات الخيوط/المعاملات الأخرى: عندما كان لديّ عدة مؤشرات ترابط تنفيذ DataService.executetransaction () في نفس الوقت ، سأحصل على AccessViolationExceptions و NullReferenceExceptions ، في الأساس قليلاً من الفوضى. لكن التغيير للاستخدام شوكة بول من Subsic مع SQLDATAPROVIDER المحدثة وأيضًا تغيير الاستخدام System.Data.Sqlite v1.0.65.0 يبدو أنه إصلاحه على الفور. الصيحة!

تحديث: في الواقع ما زلت أواجه مشاكل في الخيوط باستخدام SUBING مع SQLITE. في الأساس ، لم يتم كتابة SQLitedataprovider في Subsonc للتعامل مع MultiThreading. المزيد قادم...

نحن نستخدم SQL Lite للاختبار هي التعليمات البرمجية المتعلقة بإجراءات قاعدة البيانات. SQL Lite لا يدعم المعاملة المتداخلة. كان لدينا مشكلات مماثلة حيث كان لدينا معاملة nhibernate و .net. في النهاية ، اضطررنا إلى الاستقرار باستخدام SQL Express لاختبار الكود المتعلق بقاعدة البيانات.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top