• 0
الغملاسي

الشموع الموقَدات لكشف تضارب البيانات

سؤال

( الشموع الموقــَدات لكشف تضارب البيانات )

السلام عليكم

في هذه المقالة سنتطرق لموضوع تضارب البيانات concurrency violation الغير واضح المعالم.

لماذا؟ السبب أن الحلول متعددة بحيث تعتمد على وضع و وقت و كيفية التضارب.

ناهيك عن تعدد أنواع التضارب , لذلك أوقدنا الشموع لرؤية هذا التضارب عن كثب.

هنالك على حسب علمي المتوضع ثلاثة وضعيات أو استراتيجيات لهذه المشكلة وهي كالتالي:

أولاً ما يعرف بـ استراتيجية التضارب المشؤوم pessimistic concurrency strategy.

ثانياً: ما يعرف بـ استراتجية التضارب المحمود optimistic concurrency strategy .

ثالثاً: ما يعرف بـ استراتيجية الاخر هو الاولى Last in wins strategy .

لكن قبل كل ذلك, ينبغي علينا تعريف مالمقصود بـتضارب البيانات.

هي عملية تحدث بين مستخدمين أو أكثر بحيث يقومان بالعمل على نفس البيانات في نفس الوقت

هذه العملية كما تعلمون تعرف بـ concurrency violation

متى يقع التضارب ؟

تقع المشكلة عند عملية التحديث سواءً في الاضافة أو التعديل او الحذف, لكن ليس في عملية الاختيار Select Statement

إلا ان عملية الاختيار, كما سيأتينا لاحقاً انها كذلك لم تسلم من عملية تضارب البيانات. وإن كان البرنامج يعمل كما ينبغي.

إلا ان المعطيات ستكون غير صحيحة.

هنالك تفسير إيجابي للتضارب وهو :

Maximize the amount of work that can be done by all users at the same time, and most

importantly, make all users feel like they’re important

الاستراتيجية الاولى : استراتيجية التضارب المشؤوم pessimistic concurrency strategy.

الوضع : ان يكون فقط مستخدم واحد يُحدث في نفس الوقت, وهذا المستخدم غير مشروط

ربما يكون عمر في المرة الاولى ويكون زيد في المرة الثانية. من يجلب البيانات أول هو احق بالتحديث عن سواه.

الاستراتيجية الاولى تعتمد على غلق الحقل الذي هو قيد الاستخدام كتحديث حتى ينتهي منه المستخدم الحالي

ثم بعد ذلك يفتح هذا الحقل للمستخدم الاخر. لكن لن يتم اعتماد تحديث المستخدم الاخر, هذه العملية تعرف بـالتحديث

المفقود a lost update.

على سبيل المثال زيد وعمر قاما بجلب بيانات عامود الراتب الشهري,

وكان الصف الاول فيه القيمة 5000 درهم,

تم قفل الحقل لمصلحة زيد, زيد زاد على الصف الاول 1000 درهم

الان البيانات لن تصل إلى عمر, وعمر ما زال ينتظر عملية جلب البيانات,

ولن يفلح, حتى يفرغ زيدٌ منها, الان قام زيد بالتحديث فاصبحت 6000 درهم.

تم فتح القفل عن الحقل, الان وصلت البيانات إلى عمر 6000 درهم .

عمر قام بانقاص 2000 درهم لتصبح 4000 درهم , قام عمر بتحديث البيانات.

لم يقبل التحديث لان التحديث المقفول بزيد لا يمكن تخطيه بتحديث عمر الغير مقفل في بداية الامر

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

لذلك يعرف تحديث عمر بالتحديث المفقود lost update و الراتب الشهري في النهاية هو 6000 درهم .

ملاحظة: بما أن الحل متعلق بقفل الحقل, فهو واضح انه لا يدعم تقنية الاتصال المنقطع Disconnected environment

الاستراتيجية الثانية : استراتجية التضارب المحمود optimistic concurrency strategy .

الوضع : ان يكون اعتماد التحديث للبيانات متزامن مع الطرفين.

الاستراتيجية الثانية لا تعتمد على غلق الحقل, انما تعتمد على من يحدث اولاً قبل الاخرين.

لنفترض ان مستخدمان قاما بجلب البيانات و كانت قيمة الصف , عبارة عن حجز تذكرة

وباقي من كراسي الغير محجوزة 5 كراسي , قام المستخدم الاول بإعتماد الحجز له فاصبحت

4 وبما ان الحقل غير مقفل اثناء عمل المستخدم الاول عليه,

استطاع المستخدم الثاني جلب البيانات وهي 5 الان المستخدم الاخر قام بحجز كرسي له فاصبحت 4

قام بالتحديث , تم قبول التحديث ,الان قام المستخدم الاول ليحدث نفس الحقل بالقيمة 4

تم رفض التحديث كون القيمة العائدة هي القيمة الحالية وهي 4 كراسي فقط

و كذلك قيمة الصف القديمة ليست مطابقة للقيمة الاصلية في قاعدة البيانات والتي كانت 5 كراسي .

في الاخير, تم اعتماد حجزي المستخدمان مع ان الكراسي المحجوزة هو كرسي واحد فقط

بمعنى اخر تم حجز كرسي لشخصين...

متى يحدث التضارب المحمود : يحدث عندما يجلب مستخدم قيمة ما ويقوم الاخر

بجلب نفس القيمة ثم يغيرها ويحدثها , ثم يقوم الاول بمحاولة تحديث القيمة

التي تغيرت بواسطة المستخدم الاخر , هنا تقع المشكلة أو ما يعرف بـ optimistic concurrency violation

لماذا : لانه شرط هذه التقنية أن شرط التحديث يعتمد على التحقق من البيانات المُحدثة الحالية Current

مع البيانات الاصلية في قاعدة البيانات Original Data .

ملاحظة: الـ Dataset مصصمة لأجل هذه التقنية وهي داعمة لها و تتبناها.

الاستراتيجية الثالثة : استراتيجية الاخر هو الاولى Last in wins strategy .

الوضع : هو أن من يحدث أخرًا لا يفقد تحديثه.

الحل الثالث : لا يعتمد على غلق الحقل, انما يعتمد على من يحدث اخرًا بعد الاخرين.

لنفترض ان مستخدمان قاما بجلب البيانات و كانت قيمة الصف , عبارة عن حجز تذكرة

وباقي من كراسي الغير محجوزة 5 كراسي , قام المستخدم الاول بإعتماد الحجز له فاصبحت

4 وبما ان الحقل غير مقفل اثناء عمل المستخدم الاول عليه,

استطاع المستخدم الثاني جلب البيانات وهي 5 الان المستخدم الاخر قام بحجز كرسي له فاصبحت 4

قام بالتحديث , تم قبول التحديث ,الان قام المستخدم الاول ليحدث نفس الحقل بالقيمة 4

تم قبول التحديث وتم فقد قيمة تحديث المستخدم الاول وهي 4 كراسي فقط

تم اعتماد حجز المستخدم الاخر ,مع ضياع قيمة تحديث المستخدم الاول.

لماذا: لاسبب بسيط أن هذه التقنية لا تعتمد على تدقيق تطابق البيانات المُحدثة

بالبيانات الاصلية في قاعدة البيانات.

ملاحظة: اعتماد شرطية المفتاح الاساسي أو وقت التحديث أو رقم الصف, هي احدى حلول هذه الوضعية.

الحلول المطروحة: لمشكلة التضارب المشؤوم pessimistic concurrency strategy.

الحلول كثيرة باستخدام احدى عوازل العنصر transaction المتوفرة في النسخة 2005

لنتعرف على هذه الحلول بالتعرف على العوازل و انوعها.

مستوى العزل isolation level

ماهو مستوى العزل : هو عزل عملية التحديث الكلي transaction عن تحديث كلي أخر transaction

هنالك ثلاثة عوائق عند عملية التحديث الكلي وهم كالتالي :

اولاً : القراءة القذرة Dirty Read

ثانياً : القراءة المتعجلة non repeatable Read

ثالثًا : القراءة الوهمية phantom Read

القراءة القذرة Dirty Read تحدث هذه القراءة عندما يقوم مستخدمان أو اكثر, بالتعامل مع بيانات تم

رفض تحديثها عن طريق عملية التراجع عن التحديث Roll back عبر مستخدم ثالث.

على سبيل المثال: قام المستخدم الاول بتحويل 100 درهم من أموال الحساب الجاري وهي 500 درهم

إلى حساب التوفير الذي ليس به شيء,ومع ان حساب الجاري مقفل إلا ان المستخدم الاخر استطاع أن

يجلب قيمة الحساب الحالية وهي بعد التحول اصبحت 400 درهم, قام المستخدم الاول بعملية التحديث

إلا أن التحديث قد فشل , لسببٍ ما , على سبيل المثال حساب التوفير أغلق.. الان تمت عملية

التراجع Roll back أُعيدت المئة درهم لحساب الجاري و تم فتح القفل, لكن لازال المستخدم

الاخر يتعامل مع الراتب على اساس 400 درهم, لذلك هذا المنطق يعرف بالقراءة القذرة.

القراءة المتعجلة nonrepeatable Read تحدث عندما نقوم بقراءة بيانات تم تحديثها اثناء قرائتنا لها.

على سبيل المثال: قام المستخدم الاول بتشغيل تقرير الرواتب وكان حينها 1000 درهم للموظف الاول

في نفس الوقت كان مستخدم اخر يستخدم الحقول نفسها , حيث قام بزيادة راتب الموظف بـ 500 درهم

فبينما يفترض أن يكون راتب الموظف الاول هو 1500 درهم

إلا ان التقرير كان يعرض الراتب على اساس 1000 درهم فقط, لذلك يعرف هذا المنطق بالقراءة المتعجلة.

القراءة الوهمية phantom Read تحدث عندما نقوم بقراءة بيانات تم أضافة بيانات أخرى معها ولم ندركها.

على سبيل المثال: قام المستخدم الاول بتشغيل تقرير الرواتب وكان حينها 1000 درهم للموظف الاول

في نفس الوقت كان مستخدم اخر يستخدم الحقول نفسها , حيث قام بأضافة علاوة بدل الزوجية

بمبلغ 500 درهم , وبما أن العلاوة لم تكون حاضرة وقت تحميل التقرير

فهي قيمة مجهولة للمستخدم الاول , لذلك كان يفترض أن يكون المجموع في التقرير 1500 درهم

إلا ان التقرير كان يعرض الراتب على اساس 1000 درهم فقط, لذلك يعرف هذا المنطق بالقراءة الواهمة.

اي القراءة الغير صحيحة أو القراءة الظالمة.

الخيارات المتوفرة في مستوى العزل في SQL Server 2005

Chaos هذا الخيار غير مدعم في الـ SQLClient, ومدعم عبر الـ ADO.NET بشكل عام,

مثلاً في ADODB يعرف بـ adXactChaos , وهو عازل عنيد لايسمح بالكتابة على البيانات التي يتعامل معها.

ReadUncommitted هذا الخيار هو أقل مستوى للعزل (حيث تنطبق عليه المعوقات كلها)

وهو واضح من اسمه انه يقرء حتى القيمة التي لم تكون في الوضع Committed .

ReadCommitted: هذا الخيار الافتراضي ينتظر القيمة التي في وضع التعديل, حتى تصبح Committed

فيكمل المهمة أو يقوم بالتراجع. هذا الخيار لا يستطيع أن يعدل ما يتم تعديله من عنصر أخر,

بينما العناصر الاخرى تستطيع تعديل ما يعدله هذا الـ transaction

هذا العنصر يستخدم Row Versioning كإحدى الثوابت التي يعول عليها في عملياته.

الـ Row Version هو عبارة عن صف ينشأ في قاعدة البيانات tempdb كنوع من

الثوابت لمعرفة اخر حاله للصف قبل التعديل. يتم ذلك عبر specific transaction عنصر خاص يقوم

بعملية الربط بـ Link List بحيث تسند قيمة الصف في قاعدة البيانات الاصلية

بينما تسند نسخة الصف Version في قاعدة البيانات tempdb .

كذلك يستخدم الاقفال المشتركة shared locks لمنع القراءات القذرة ,لكن البيانات

يمكن تغيرها قبل ان ينتهي هو من مهامه , لذلك القراءة المتعجلة و الوهمية nonrepeatable & phantom reads,

احتمالية حدوثها واردة لا محالة.

ملاحظة: لإستخدام هذا النوع من العزل على قاعدة البيانات المعنية, نفذ هذا الكود.READ_COMMITTED_SNAPSHOT

RepeatableRead: هذا الخيار لا يستطيع أن يعدل قيمة لم يحن إعتمادها ولا يستطيع عنصر

اخر ان يعدل ما يتم تعديله في هذا العنصر الحالي, حتى ينتهي منها ويتم اعتمادها Committed .

هذا العنصر يستخدم الاقفال المشتركة shared locks وهذا يعني حماية البيانات المستخدمة من اي

طرف اخر, إلا للقراءة فقط, لكن المشكلة أنه يسمح كذلك بإضافة صفوف جديدة,

مما يسهم في مشكلة القراءة الوهمية Read phantom .

:Serializable هذا الخيار هو أعلى مستوى للعزل (حيث لا تنطبق عليه المعوقات كلها)

يُمنع هذا العزل من قراءة بيانات تستخدم من قبل الاخرين, وكذلك يمنع اي عنصر خارجي باستخدام

ما هو قيد التعديل عنده.حتى الاضافة يمنعها فلا يسمح بإخال صف جديد ضمن الصفوف التي لديه

حتى ينتهي منها. فهو عازل صارم للغاية.

Snapshot هذا الخيار يستخدم نسخة الصف كذلك Row Versioning في بدء عملياته,

هذا الخيار تُحجب عنه الصفوف التي يتم التعديل عليها من اطراف اخرى,فهو يرى فقط البيانات

التي لم تمس من قبل الاخرين. وهو لا يتطلب قفل الصفوف عند عملية القراءة ,إلا أنه يستخدمه

في عملية التراجع عن التعديل Rolled Back .

ملاحظة: لإستخدام هذا النوع من العزل على قاعدة البيانات المعنية , نفذ هذا الكود.

ALTER DATABASE Northwind
SET ALLOW_SNAPSHOT_ISOLATION ON
GO()

Unspecified غير محدد.

ملاحظة : العوازل الـ 6 مدعمة جميعها في الـ Compact framework

نصائح في استخدام العزل المناسب للمشاريع

العزل ReadUncommitted يفضل في المشاريع التي يتم التعامل مع البيانات بشكل سريع وفي اقصر وقت.

العزل RepeatableRead يفضل في المشاريع التي تتطلب دقة كاملة في تشغيل التحديثات التامة , مع ضمان منع

اي تحديث من اطراف اخرى, حتى ينته الحالي من عمليته الحالية.

العزل Serializable يفضل في المشاريع التي تتطلب دقة تامة عند التعامل مع البيانات , بحيث تمنع حتى عملية

الادخال من اطراف اخرى , حتى ينتهي الـ transaction من عمليته .

العزل Snapshot يفضل في المشاريع التي تستخدم محاسبات معقدة و لغرض القراءة فقط.

في الاخير وبلا ادنى شك أن هذا الفتات لا يغطي حقيقة تقنية العزل, إلا ان المقالة جرتنا للخوض فيه.

شاهد النصوص البرمجية لذلك.

' If no item of combobox selected
If Me.cboxIsoLevel.SelectedIndex < 0 Then
MsgBox("ComboBox is required in Pessimistic Strategy ")
Return
End If

' Create a connection object for datareader.
Using Cnn As New SqlConnection(My.Settings.NorthwindConnectionString)

' Open the connection object.
Cnn.Open()

' Note that you have to alter Northwind database
' Enable the Read Committed with Snapshots isolation level
' Script example...
' *******************************
' ALTER DATABASE Northwind
' SET ALLOW_SNAPSHOT_ISOLATION ON
' GO()
' *******************************

' Create local transaction.
Using transaction As SqlTransaction = _
Cnn.BeginTransaction(IsolationLevel.Snapshot)

' Create local command object.
Using cmd As New SqlCommand(Nothing, Cnn)

' Assign command transaction property
' To transaction object.
cmd.Transaction = transaction

Try

' Create query that update contactname
' Depend on ALFKI id.
Dim strCommand As String = _
"Update Customers SET ContactName = '" & txtPessimistic.Text & _
"' WHERE CustomerID = 'ALFKI'"

' Assign the query to command text property.
cmd.CommandText = strCommand

' Execute updates.
cmd.ExecuteNonQuery()

' Sleep for 10 seconds, for testing purposes.
Threading.Thread.Sleep(10000)

' Push(Data)
transaction.Commit()

' Clear dataset and refill it again.
FillData()

' Handling concurrency exception.
Catch ex As DBConcurrencyException
MsgBox(ex.Message)

' Handling others exception.
Catch ex As Exception
MsgBox(ex.Message)
End Try
End Using

' Implicitly disposes (closes) connection,
'and rolls back transaction (if not already committed).
End Using
End Using
End Sub

الحلول المطروحة: لمشكلة التضارب المحمود optimistic concurrency strategy.

الحل الاول : استخدام الحدث RowUpdated Event التابعة للـ DataAdpater بهي نستطيع أن

نعرف هل حدث التصادم أم لا و ببعض خصائصه نتحكم بالخطأ الذي صدر من صفٍ ما .

الحل الثاني: هو تمكين الخاصية ContinueUpdateOnError بحيث تساوي True لتكملة التحديث حتى وان كان

هنالك خطأٌ ما في صفٍ ما, بحيث يقوم بتخطي الخطأ دون تحديثه, مع استمرار تحديث الصفوف التي بعده.

هذه الخاصية : تمنع إنهيار أو تجمد البرنامج , وكذلك تمنع رسالة الخطأ الافتراضية .

الخاصية ContinueUpdateOnError هي احدى خواص الـ DataAdapter .

ثالثاً : يمكنك امساك التضارب عبر القالب

DBConcurrencyException

شاهد النصوص البرمجية لعمل ذلك.

نكتب هذا الكود في صفحة الـ DataSet.vb

Imports System.

Handling_Database_Operation_Conflicts.rar

تم تعديل بواسطه الشهاب الحارق
1

شارك هذا الرد


رابط المشاركة
شارك الرد من خلال المواقع ادناه

29 إجابة على هذا السؤال .

  • 0

مقال رائع , فعلا رائع

لي سؤالين اخي , الاول هذ الكود لم افهم فائدته

' Sleep for 10 seconds, for testing purposes.
Threading.Thread.Sleep(10000)

' Push(Data)
transaction.Commit()

' Clear dataset and refill it again.
FillData()

والثاني لماذا استخدمت using , وما فائدتها , اي بماذا تقوم ؟؟؟؟؟

0

شارك هذا الرد


رابط المشاركة
شارك الرد من خلال المواقع ادناه
  • 0

مقال رائع أستاذنا الغملاسي

0

شارك هذا الرد


رابط المشاركة
شارك الرد من خلال المواقع ادناه
  • 0

السلام عليكم

Sleep for 10 seconds, for testing purposes.

Threading.Thread.Sleep(10000)

' Push(Data)

transaction.Commit()

' Clear dataset and refill it again.

FillData()

طيب استخدمنا الاجراء Sleep حتى نعطي فرصة للتضارب, اي هذا السلوك فقط لاجل الاختبار لا اكثر

بحيث لوقمت بالتحديث ثم ذهبت للنسخة الثانية من نفس البرنامج لتختبر التضارب بين القيم تكون هنالك شيء من الثواني المتبقية

مما تعطل البرنامج عن التحديث حتى تقوم بالتحديث من النسخة الثانية فيحصل التضارب ,

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

وهذا ما لا يتوفر لديك ولدي لذلك قمنا بهذه الحيلة حتى فقط نختبر التضارب لا أكثر , واما في الميدان العملي فإن هذا الكود يحذف برمته حتى لا يتسبب

في خلق المشكلة التي نحنُ بصدد حلها أو التقليل منها إن صح التعبير.

اما transaction.Commit() فهو دفع التحديث دفعة واحدة إلى قاعدة البيانات

لان منطق التحديث عبر الـ transaction هو اما التحديث دفعة واحدة كل البيانات أو لا تقم بالتحديث إطلاقاً

لانه لا يقوم بتحديث صفوف ويترك بعضها , لا إنما اما التحديث الكلي او لا .

اما الاجراء FillData() هو يقوم فقط بعملية ازالة كل الصفوف من جداول الـ Dataset ثم يقوم بتعبئتها من جديد.

فقط لتشاهد اخي الكريم التحديثات بشكل مرئي بعد كل عملية تضارب لا أكثر.

بالنسبة لاستخدام الـتعبير Using Statement فهي ذات فائدة عظيمة.

أولاً أنها تضمن لي ان العنصر الذي استخدمه في هذا التعبير هو عنصر محلي لا يعرف في مكان اخر.

وهذا يحمي نصوصي البرمجية من التداخل بينهما.

ثانياً هي تتكلف عني بعناء قتل العنصر و حذفه من الذاكرة بمجرد وصول المترجم عند النقطة End Using او ما يعرف بنهاية الـ Block

وهذا يوفر عليه ايضاً الوقت و الجهد بكتابة مثلاً myObject.Dispose ثم اكتب بعدها myObject = Nothing

وهذا حتى لو ظهر خطأٌ ما ستقوم بقتل العنصر إلا الخطأ StackOverflowException. وهذا منهوه عليه في الـ MSDN

وهو موقع المبرمجين لهذه اللغات.

ثالثاً: هي تقريباً مشابه لعمل التعبير Try statment إلا انها تميزت كما ذكرنا آنفًا بالتولي بحذف العناصر من الذاكرة.

مقال رائع أستاذنا الغملاسي
شكراً يا استاذي العزيز.

بالتوفيق إن شاء الله.

0

شارك هذا الرد


رابط المشاركة
شارك الرد من خلال المواقع ادناه
  • 0

اشكر اخي على هذا التوضيح , وشكرا على المقال مرة اخري فهو اكثر من رائع

0

شارك هذا الرد


رابط المشاركة
شارك الرد من خلال المواقع ادناه
  • 0

الف شكر استاذنا الغملاسى

لى عدة استفسارات سوف ارجع لها في وقت اخر

لي طلب من المشرف المتالق samerselo او اي مشرف اخر

هو وضع هذا الموضوع ضمن قائمه المواضيع الثابته او المطلوبه او عمل قسم للمقالات المهمه متل هذه

لانو موضوع مثل دا يجب استمراره مع استمرار المنتدي لعدم وجود مقالات اخرى في المنتدي تغطي هذه الجوانب

يعطيك الف عافية على هذا الموضوع وشكرا

0

شارك هذا الرد


رابط المشاركة
شارك الرد من خلال المواقع ادناه
  • 0

السلام عليكم

الاخ الكريم الغملاسى

يعطيك العافية على هدا الموضوع

في اول نقطه انتا ذكرتها حول التضارب المشئوم

هدا الجانب الوحيد حصلت مقالات تتحدث عن هدا النوع

لكن بصراحه ومن وجهت نظرى كمبتدة

ارى انه فيه تناقض في النقطة دي لانو كيف يكون هناك تضارب ويكون في بيئه متصله اي ان هدا النوع كما ذكرت لايدعم الاتصال المنفصل

عمليا يعني راح يكون المستخدم شخص واحد ( راح تكون هذه طريقه غبية في حال كان البرنامج يخدم اكثر من مستخدم لهذا النوع من الاتصال) يعني احتمال التضارب فقط يكون في نوع الداتا تايب عند الادخال

هذا كان راى مبتدئة في البرمجه فارجو المعذره ادا كان خطا بس لانو دي النقطه لم اقتنع فيها

ناتي الان الى الموضوع الاهم بالنسبة لى

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

ان هناك ثلاث طرق في حلها

بالنسبة للحل الثاني لهذه الاستراتيجية

هل الكود التالى هو الطريقة الصحيحه في استخدامه

 Dim ds As New DataSet()
Dim con As New OleDb.OleDbConnection()
Dim sql As String = "select cl,dmn from DTMain "
con.ConnectionString = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source= " & _
Application.StartupPath & "\sand.mdb"



Dim dp As New OleDb.OleDbDataAdapter(sql, con)
dp.Fill(ds, " DTMain ")
Dim SearchRow() As DataRow = ds.Tables("DTMain").Select( _
"cl =" & TextBox1.Text, "cl")
'اختيار صف معين واجراء عملية التغير عليه
For Each dr As DataRow In SearchRow
dr("dmn") = TextBox2.Text.ToString
Next
'هنا نحدث فقط الصف الذى حصل له التحديث
'نرى ادا كان هناك اي تحديث على الداتا ست
'لنحدث على قاعدة البيانات الاصلية
If ds.HasChanges Then
Dim AffectedDS As DataSet = ds.GetChanges
Dim ComBuilder As New OleDb.OleDbCommandBuilder(dp)
dp.ContinueUpdateOnError = True

dp.UpdateCommand = ComBuilder.GetUpdateCommand
dp.Update(AffectedDS, " DTMain ")


Dim ConflictRow As DataRow
Dim ConfilctRowCount As Integer = AffectedDS.Tables("DTMain").GetChanges.Rows.Count
For Each ConflictRow In AffectedDS.Tables("DTMain ").Rows
If ConflictRow.RowState = DataRowState.Modified Then
MessageBox.Show(" حدث خطاء في تحديث الصف" & ConflictRow(1), "تعارض تحديث البيانات", "تعارض")
End If
Next
End If

هذا الحل هو اجتهاد شخصي بعد ان قراءت من عدة كتب ذكرت بشكل بسيط هذه النقطه

فارجو تصحيحه لى ادا كان هناك اي خطاء فيه

وارجو ايضا ابلاغي في حال كانت الطريقه صحيحه لكي اعتمدها في مشروعي

بالنسبة للحل الثالث من نفس الاستراتيجيه (التضارب المحمود ) للاسف لم اقم بتجربتها لوجود عده نقاط لم افهمها( ادا استحال علي فهمها سوف استفسر عنها لاحقا)

بالنسبة للمرفقات للاسف ليس لدي sql server على الجهاز لذلك لم اقم بتجربتها ( عفوا المرفقات تابعه لاي حل ؟)

شكرا اخي الكريم

ويعطيك الف عافية

0

شارك هذا الرد


رابط المشاركة
شارك الرد من خلال المواقع ادناه
  • 0

السلام عليكم

ارى انه فيه تناقض في النقطة دي لانو كيف يكون هناك تضارب ويكون في بيئه متصله اي ان هدا النوع كما ذكرت لايدعم الاتصال المنفصل

عمليا يعني راح يكون المستخدم شخص واحد ( راح تكون هذه طريقه غبية في حال كان البرنامج يخدم اكثر من مستخدم لهذا النوع من الاتصال) يعني احتمال التضارب فقط يكون في نوع الداتا تايب عند الادخال

راجعي المعوقات الثلاث للتحديث الكلي, في بطن المقالة.

بالنسبة للكود المعروض هو نصف الحل, ليس إلا , رغم بعض التحفظات على بعض السلوكيات المستخدمة فيه

ومنها ما لا يفنجر fired حتى ولو جاء وقت الانفجار ,

لكن كل هذا لا يسلم به, بسبب اني لم اختبر الكود , لكن في المرفق ما يتوافق مع النصوص المعروضة.

بالتوفيق إن شاء الله.

0

شارك هذا الرد


رابط المشاركة
شارك الرد من خلال المواقع ادناه
  • 0

السلام عليكم

استاذنا الكبير الغملاسي اشكرك على هذا الموضوع المهم و الشيق و الذي يصادف الكثير من المبرمجين

اخي الغالي الغملاسي انا فكرت في طريقة و هي ان اضع تايمر يراقب الجدول عن طريق

if adapter1.rowupdated=true then

احصل على نسخة جديدة من الداتا سيت باعتبار الداتا سيت التي اعمل عليها اصبح عليها تعديل

else

اكمل العمل بوضع اعتيادي

و اريد ايضاَ اخي الغالي السؤال كيف احل مشكلة واجهتني الا وهي اذا غيرت قيمية معينة باني قمت بتعديل قيمة من محمد الى احمد مثلاُ و قام مستخدم آخر بالتعديل على نفس القيمه من محمد الى حسام ماذا سوف يحدث اتمنى ان تجيب على هذا الاتفسار و اتمنى ان لا اكون ازعجتك بسؤالي و شكرا جزيلاً لك

ملاحظة اخي الغالي اتمنى ان يكون هناك مثال مرفق مع الشرح بقاعدة بيانات آكسس لاني للاسف ما اعرف اس كيو ال

و شكراً جزيلاً لك

0

شارك هذا الرد


رابط المشاركة
شارك الرد من خلال المواقع ادناه
  • 0

السلام عليكم

جزاك الله خيرا يا مشرفنا على هذا الموضوع

ولدي سؤال

من الواضح ان ال concurrency violation لا يحدث الا عند وجود اكثر من مستخدم للداتا بيز

ولكن لدي مشروع على 2005 وهو لمستخدم واحد ويحدث هذا الايرور فيه في بعض الاحيان و احيان اخرى لا يحدث

ولا اعلم ما السبب حتى انني اعتقدت انه خطأ في 2005 لان نفس الكود لا ينتج عته هذا الخطأ في 2003

مع العلم انا استخدم ال Disconnected Enviroment

وجزاكم الله خيرا

0

شارك هذا الرد


رابط المشاركة
شارك الرد من خلال المواقع ادناه
  • 0

لا أقول الا ...

أكثر من رااااااااااااااائع يا عملاسي

0

شارك هذا الرد


رابط المشاركة
شارك الرد من خلال المواقع ادناه
  • 0

كلام GalalDev صحيح

انا معى نفس المشكله

0

شارك هذا الرد


رابط المشاركة
شارك الرد من خلال المواقع ادناه
  • 0

الأخ الشهاب الحارق جزاك الله خير على هذا الموضوع الذي كنت ابحث عنه من زمان

لكن ارجو حبة حبة تقدم لي افضل حل لحالة التالية:

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

ارجو منك الإفادة وجزاك الله خير

0

شارك هذا الرد


رابط المشاركة
شارك الرد من خلال المواقع ادناه
  • 0

السلام عليكم

hussientafserqa

وضع timer يراقب قاعدة البيانات ( فكرة سيئة للغاية )

لأسباب كثيرة ( ان هذا الحدث يوجد من ضمن خصائصة ما يمنعه عن المراقبة)

ويفضل أن تبدء المسألة من قاعدة البيانات أولاً ثم في الـ Object Code ثم أخيراً في الـ Form Code.

هنالك أحداث كثيرة هي أفضل من التوقيت على سبيل المثال rowupdated .

اذا غيرت قيمية معينة باني قمت بتعديل قيمة من محمد الى احمد مثلاُ و قام مستخدم آخر بالتعديل على نفس القيمه من محمد الى حسام ماذا سوف يحدث اتمنى ان تجيب على هذا الاتفسار

هذا الاستفسار اجبنا عليه وهو يعتمد على الطريقة التي تُحدث بها قاعدة البيانات,

هل هي عن طريق التضارب المشؤوم أو التضارب المحمود أو الاخر هو الاولى.

راجع المقالة للإستزادة.

اتمنى ان يكون هناك مثال مرفق مع الشرح بقاعدة بيانات آكسس لاني للاسف ما اعرف اس كيو ال

المشكلة ان Access يحرمنا من اهم الطرق وهو التحديث الكلي أما الكل او لا .

على فكرة الـ SQL ليس بالامر الصعب لكن التدرج فيه مطلوب حتى تستسيغه.

GalalDev

ولكن لدي مشروع على 2005 وهو لمستخدم واحد ويحدث هذا الايرور فيه في بعض الاحيان و احيان اخرى لا يحدث

هذا يحدث بسبب عدم تزويد التحديث بالمفتاح الاساسي للجدول(و بالتحديد عندما تطبق منطق جدول الاب و الابن)

تحدث هذه المشكلة حينما يراد تحديث جدول الابن بالمفتاح التابع لجدول الاب الغير محفوظ في قاعدة البيانات .

لذلك حدث جدول الاب أولاً ثم اتبعه بالابن , و العكس صحيح في عملية الحذف.

beeerooo

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

إذا كان القصد ان كل شخص يقوم بالتحديث , يمنع بالمقابل الاشخاص الاخرين , فهذا عن طريق التضارب المشؤوم

ذكرناه في المقالة

أما إن كنت تقصد ان التحديث يخصك انت و يستثني غيرك , فهذا تحدده عن طريق صلاحيات قاعدة البيانات

بأن تجعل العامود qty في الجدول يتضمن تحديث من قبل الـ Account لديك فقط أو لك و لغيرك ممن يختص بهذا.

وفق الله الجميع لما فيه الخير و البركة.

0

شارك هذا الرد


رابط المشاركة
شارك الرد من خلال المواقع ادناه
  • 0

نعم اخي شهاب الذي اقصده هو الأول وهو ان كل شخص يقوم بالتحديث , يمنع بالمقابل الاشخاص الاخرين , فهذا عن طريق التضارب المشؤوم

وانا اعلم انك ذكرته في المقالة بارك الله فيك بس لو تكلف على نفسك شوي وتيجي على قد عقلي وتعطينا مثال ثاني يكون فيها تحديث كميات الأصناف ويكون فيه شوية شرح توضيحي زيادة. .... يعني تكون مشكور ومش هنعرف نودي جمايلك فين.

هل هذه الطرق تختلف من قاعدة بيانات sqlserver أو oracl او اaccess??

وبالمرة طالما ان الموضوع اتفتح هل يوجد طريقة لقفل الجدول بمعنى عمل له lock وعدم تمكين اي شخص اخر للوصول اليه حتى يتم فتحه unlock حث قد احتاج هذه الطريقة لعمل صيانة للبيانات؟

شكرا شهاب

تم تعديل بواسطه beeerooo
0

شارك هذا الرد


رابط المشاركة
شارك الرد من خلال المواقع ادناه
  • 0

السلام عليكم

اخي beeerooo أرفقت مثال للمشروع , عسى ان يوضح الفكرة أكثر ,, والله يسهل علينا و عليكم

السلام عليكم.

0

شارك هذا الرد


رابط المشاركة
شارك الرد من خلال المواقع ادناه
  • 0

حقيقي ربنا يبارك فيك يا اخي ومعلومات مفيدة جدا

0

شارك هذا الرد


رابط المشاركة
شارك الرد من خلال المواقع ادناه
  • 0

السلام عليكم ورحمة الله وبركاته ..

لقد تفاجأت بمشكلة لم أجد لها حل ، وهي متعلقة بـانتهاك التزامن ..

وذلك عندما أضيف صف جديد وأقوم بحفظه مباشرة ، وبعد ذلك عند رغبتي في تعديل قيمة الصف المضاف للتو تواجهني مشكلة انتهاك التزامن حيث تظهر لي هذه الرسالة :

System.Data.DBConcurrencyException: انتهاك التزامن: أثّر UpdateCommand على 0 سجل (سجلات) من إجمالي 1 سجل (سجلات) متوقع.

فهل هذه المشكلة لها علاقه بتظارب البيانات ، وما الحل ، ارجو الإضاح مشكورين ..

سوف أرفق مثال على ذلك ...

UpdateCommand.zip

0

شارك هذا الرد


رابط المشاركة
شارك الرد من خلال المواقع ادناه
  • 0

الحل: أن تنهج غير النهج الذي تطور فيه مشاريعك, فالمشروع لا schema file ولا هو مكتوب بالشكل الصحيح من حيث إضافة و تحديث

البيانات , لذلك فقدان المفتاح الاساسي في عملية التحديث وقبل إنهاء تحرير الجدول سيعود بهذه المشكلة ,

قلنا لك اخي من قبل , اعفي نفسك عن غلوئِها و انظر في جلب البيانات و إنشاء Strong dataset بدل كتابة ذلك بشكل يدوي.

والله المستعان.

تم تعديل بواسطه الشهاب الحارق
0

شارك هذا الرد


رابط المشاركة
شارك الرد من خلال المواقع ادناه
  • 0
فالمشروع لا schema file ولا هو مكتوب بالشكل الصحيح من حيث إضافة و تحديث

البيانات

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

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

0

شارك هذا الرد


رابط المشاركة
شارك الرد من خلال المواقع ادناه
  • 0
ولكني أحببت الكود وأجد أنه يلبي جميع طلباتي

أخي بارك الله فيك , من قال لك أننا نكره الكود و انه لا يلبي طلبنا, ولكن المهم في الامر هو

متى تستخدم الكود و متى تريح نفسك بما ينوب عنه .

دع العجلة تدور و حاول أن تسير في خطى الركب, لا أن تقف و تقول كيف لها أن تدور.

ولو مكثت تحاول في كتابة الكود بشكل يدوي ( ربما يفوتك الشيء الكثير ) وقد تفاجئ غداً بطريقة أخرى في تعريف تلك الاكواد.

إذا ما اصدرت إصدارةٌ اخرى. والله الموفق.

0

شارك هذا الرد


رابط المشاركة
شارك الرد من خلال المواقع ادناه
  • 0

سوف استخدم المعالج ، ولكن هل نقول أنه لا يوجد حل لتلك المشكله بالكود ..

0

شارك هذا الرد


رابط المشاركة
شارك الرد من خلال المواقع ادناه
  • 0
ولكن هل نقول أنه لا يوجد حل لتلك المشكله بالكود
للمرة الاخيرة أقول المشكلة أنك الى الان لم تصل

الى المتسبب للمشكلة , فإنت وليس للكود اي مشكلة .

فتعلم كيف تنشئ قيمة تحديث و ادخال وحذف و اختيار و تعلم كيف تتعامل مع العناصر بمثالية عبر الكود (تحقيق لرغبتك)

ثم إذا ظهرت مشكلة بعد الاستراتيجية الصحيحة , فلا عتب عليك, لكن أن تأخذها بشكل عشوائي ثم تقول ويحهُ ما له لا يراعي.

فهذا عتاب غير منطقي ولا في محله. والله الموفق.

تم تعديل بواسطه الشهاب الحارق
0

شارك هذا الرد


رابط المشاركة
شارك الرد من خلال المواقع ادناه
  • 0
فتعلم كيف تنشئ قيمة تحديث و ادخال وحذف و اختيار و تعلم كيف تتعامل مع العناصر بمثالية عبر الكود (تحقيق للرغبتك)

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

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

Imports System.Data
Imports System.Data.OleDb

Public Class Form1

Dim ConnectionString As String = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source =" & Application.StartupPath & "\Data.mdb"
Dim MyConnection As New OleDbConnection(ConnectionString)
Dim MyDA As OleDb.OleDbDataAdapter
Dim MyDS As New DataSet
Dim WithEvents MyBS As BindingSource
Dim SQL As String

Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load

Dim SQL = "SELECT * FROM Info order by name"

MyDA = New OleDb.OleDbDataAdapter(SQL, MyConnection)
MyDA.Fill(MyDS, "Info")

MyBS = New BindingSource(MyDS, "Info")

Me.txtName.DataBindings.Add(New Binding("TEXT", MyBS, "Name"))
Me.txtAge.DataBindings.Add(New Binding("TEXT", MyBS, "Age"))
Me.txtphone.DataBindings.Add(New Binding("TEXT", MyBS, "Phone"))
Me.txtEmail.DataBindings.Add(New Binding("TEXT", MyBS, "Email"))
Me.lblPosition.Text = MyBS.Position + 1 & " OF " & MyBS.Count

End Sub

Private Sub btnFirst_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnFirst.Click
MyBS.MoveFirst()
End Sub

Private Sub btnPrevious_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnPrevious.Click
MyBS.MovePrevious()
End Sub

Private Sub btnNext_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnNext.Click
MyBS.MoveNext()
End Sub

Private Sub btnLast_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnLast.Click
MyBS.MoveLast()
End Sub

Private Sub MyDB_PositionChanged(ByVal sender As Object, ByVal e As System.EventArgs) Handles MyBS.PositionChanged
Me.lblPosition.Text = MyBS.Position + 1 & " OF " & MyBS.Count
End Sub

Private Sub btnAddNew_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnAddNew.Click
MyBS.AddNew()
End Sub

Private Sub btnSave_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnSave.Click
Dim myCB As New OleDbCommandBuilder(MyDA)
MyBS.EndEdit()
Me.MyDA.Update(MyDS, "info")
End Sub

Private Sub btnDelete_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnDelete.Click
Dim Answer As MsgBoxResult
Answer = MessageBox.Show("هل ترغب حقاً في حذف السجل الحالي ؟", "حذف السجل الحالي", MessageBoxButtons.YesNo, MessageBoxIcon.Question, MessageBoxDefaultButton.Button2, MessageBoxOptions.RtlReading)
If Answer = MsgBoxResult.Yes Then
Me.MyBS.EndEdit()
MyBS.RemoveCurrent()
btnSave_Click(Nothing, Nothing)
End If
End Sub

Private Sub btnExit_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnExit.Click
Dim Answer As MsgBoxResult
If MyDS.HasChanges = True Then
Answer = MsgBox("! لم تقم بحفظ جميع التغييرات التي قمت بها" & ControlChars.NewLine & "هل ترغب في حفظ البيانات المعدلة ؟ ", MsgBoxStyle.YesNo)
If Answer = MsgBoxResult.Yes Then
btnSave_Click(Nothing, Nothing)
End
Else
End
End If
Else
End
End If
End Sub

Private Sub btnCancel_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnCancel.Click
MyBS.CancelEdit()
MyDS.RejectChanges()
End Sub

Private Sub btnFind_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnFind.Click
Dim foundIndex As Integer = Me.MyBS.Find("Name", Me.txtFind.Text)
If foundIndex > -1 Then
Me.MyBS.Position = foundIndex
Else
MessageBox.Show("Font was not found.")
End If
End Sub

End Class

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

0

شارك هذا الرد


رابط المشاركة
شارك الرد من خلال المواقع ادناه
  • 0

اخي العزيز , لو راجعت هذا الكتاب Beginning Visual Basic®2005 Databases سيختصر عليك أمور كثيرة.

و بالله التوفيق.

0

شارك هذا الرد


رابط المشاركة
شارك الرد من خلال المواقع ادناه
  • 0

بسم الله الرحمن الرحيم

هذا الرد موجه بشكل خاص للأخ yaseralshikh بناء على طلب منه في الخاص ولكن بالطبع أرجو أن يستفيد منه الجميع

أخي ياسر

المشكلة عندك أنك تستخد الـ command bulder لبناء الكوماندات للداتا أدابتر والكوماند بلدر يبنيها بالطريقة "التفاؤلية" لأنها الطريقة الافتراضية لذلك عليك أن تبني هذه الكوماندات يدوياً

في المرفقات مشروعك مع التعديلات والتي تتضمن بناء كوماندي الأبديت والإنسيرت يدوياً

طبعاً كوماند الديليت يمكن أن يبنى بنفس الطريقة

وشكراً

UpdateCommand.rar

0

شارك هذا الرد


رابط المشاركة
شارك الرد من خلال المواقع ادناه

من فضلك سجل دخول لتتمكن من التعليق

ستتمكن من اضافه تعليقات بعد التسجيل



سجل دخولك الان

  • يستعرض القسم حالياً   0 members

    لا يوجد أعضاء مسجلين يشاهدون هذه الصفحة .