سؤال

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

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

المحلول

والمعاملات هو وسيلة جيدة للذهاب، مثل لو dorfier يقول، ولكن هناك alernatives:

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

UPDATE message
SET    user_id = ...
WHERE  user_id = 0   -- Ensures no two users gets the same message
LIMIT 1

في SQL مللي ثانية، سيكون شيئا على غرار:

WITH q AS (
  SELECT TOP 1
  FROM message m
  WHERE user_id = 0
) 
UPDATE q
SET    user_id = 1

و/ B

نصائح أخرى

وهذا ما BEGIN TRAN والالتزام TRAN هي ل. وضع البيانات التي تريد حمايتها ضمن الصفقة.

<اقتباس فقرة>   

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

ولا. SQL ليست لغة إجرائية. يمكنك إعادة كتابة ما تبذلونه من الاستفسارات اثنين كما استعلام واحد (وليس من الممكن دائما، وغالبا ما لا يستحق كل هذا العناء حتى لو كان ذلك ممكنا)، أو الغراء لهم جنبا إلى جنب مع اللغة الإجرائية. توفر العديد من خوادم SQL لغة المدمج في لهذا ( "الإجراءات المخزنة")، أو يمكنك أن تفعل ذلك في طلبك.

<اقتباس فقرة>   

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

واستخدام الأقفال. أنا لا أعرف ما الخادم SQL الذي تستخدمه، ولكن باستخدام SELECT ... FOR UPDATE يبدو أنه سيكون مجرد ما تريد، إذا كان متوفرا.

هل يمكن استخدام جدول مؤقت ربما.

وSQL نفسها ليس لديها المتغيرات، ولكن (تقريبا؟) جميع التمديدات SQL RDBMS القيام به. ولكن، لست متأكدا حقا كيف هذا وحده من شأنه أن يحل مشكلتك.

وكما ذكر، فإن الصفقة تفعل خدعة - تجمع نحو فعال 2 البيانات لا علاقة لها معا. ولكن ، فإن <م> لا تعمل على مستوى المعاملة الافتراضي . (أكثر؟) قراءة ارتكبت مستوى المعاملة الافتراضي الخادم RDBMS ل. هذا لا يمنع المستخدم 2 من قراءة نفس الصف أن المستخدم 1 قراءة. لذلك، وكنت بحاجة إلى استخدام READ للتكرار أو SERIALIZABLE.

وهذه قضية التزامن الكلاسيكية. عموما، 2 طرق التعامل معها هي تأمين متشائم أو متفائل التحقق. ومن شأن الصفقة READ تكرار نكون متشائمين (تكبد مصاريف تأمين وجود أو عدم الحاجة إليها)، والتحققROWCOUNT غير متفائل (على افتراض انه سوف يعمل، لكنه لا يفعل شيئا معقولا عندماROWCOUNT = 0).

وعادة، ونحن نستخدم متفائل (قفل مكلف)، وإما استخدام الطابع الزمني أو مجموعة من الحقول قراءة لضمان أننا تغيير بيانات كنا نظن. لذلك، اقتراحي هو لتشمل rowversion أو الطابع الزمني المجال، وتمرير ذلك مرة أخرى إلى بيان UPDATE الخاص بك. ثم، تحققROWCOUNT لمعرفة ما إذا قمت بتحديث أية سجلات. إذا كنت لا، ثم العودة واختيار رسالة أخرى. في شبه كود:

int messageId, byte[] rowVersion = DB.Select(
  "SELECT TOP 1 
      MessageId, RowVersion 
   FROM Messages 
   WHERE 
      User IS NULL";

int rowsAffected = DB.Update(
   "UPDATE Messages SET 
       User = @myUserId 
    WHERE 
       MessageId = @messageId 
       AND RowVersion = @rowVersion", 
    myUserId, messageId, rowVersion
);
if (rowsAffected = 0) 
   throw new ConcurrencyException("The message was taken by someone else");

واعتمادا على بيانات معينة، قد تكون قادرة على الابتعاد مع مجرد تكرار "معرف المستخدم IS NULL" جملة WHERE في عبارة UPDATE الخاص بك. هذا على غرار الحل Brimstedt - ولكن لا يزال يجب أن تحققROWCOUNT لمعرفة ما إذا تم تحديث الصفوف في الواقع.

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