আপডেট / ইনসার্ট সংমিশ্রণের জন্য পোস্টগ্রিসে লক করা


11

আমার দুটি টেবিল আছে একটি লগ টেবিল; অন্যটিতে মূলত, কুপন কোড রয়েছে যা কেবল একবার ব্যবহার করা যেতে পারে।

ব্যবহারকারীর একটি কুপন উদ্ধার করতে সক্ষম হওয়া দরকার যা লগ টেবিলের মধ্যে একটি সারি সন্নিবেশ করবে এবং কুপনটি ব্যবহৃত হিসাবে চিহ্নিত করবে (এতে usedকলামটি আপডেট করে true)।

স্বাভাবিকভাবেই, এখানে একটি স্পষ্ট জাতি জাতি / সুরক্ষা সমস্যা আছে।

আমি মাইএসকিউএল এর বিশ্বে অতীতে একই জিনিস করেছি। এই পৃথিবীতে, আমি উভয় টেবিলকে বিশ্বব্যাপী লক করব, এই যুক্তিটি নিরাপদে রাখুন যে এটি একবারে একবারে ঘটতে পারে, এবং তারপরে আমার কাজ শেষ হওয়ার পরে টেবিলগুলি আনলক করতাম।

এটি করার জন্য পোস্টগ্রিসের আরও ভাল উপায় কি নেই? বিশেষত, আমি উদ্বিগ্ন যে লকটি বিশ্বব্যাপী, তবে তা হওয়ার দরকার নেই - আমার কেবল সত্যই নিশ্চিত করা দরকার যে অন্য কেউ particular নির্দিষ্ট কোডটি প্রবেশ করার চেষ্টা করছেন না, তাই সম্ভবত কিছু সারি-স্তরের লকিং কাজ করবে?

উত্তর:


15

আমি এর আগে মাইএসকিউএল এর মতো সমাবর্তন সমস্যার কথা শুনেছি। পোস্টগ্রিসে তেমন নয়।

ডিফল্ট READ COMMITTEDলেনদেনের বিচ্ছিন্নতার স্তরে অন্তর্নির্মিত সারি-স্তরের লকগুলি যথেষ্ট।

আমি ডেটা-সংশোধনকারী সিটিই (এমন কিছু যা মাইএসকিউএল-তেও নেই) সহ একক বিবৃতি প্রস্তাব করছি কারণ এটি এক টেবিল থেকে অন্য টেবিলের কাছে সরাসরি মানগুলি সরবরাহ করা সুবিধাজনক (যদি আপনার এটির প্রয়োজন হয়)) আপনার যদি couponটেবিলের থেকে কিছু না প্রয়োজন হয় তবে আপনি পৃথক UPDATEএবং INSERTবিবৃতি দিয়েও লেনদেন ব্যবহার করতে পারেন ।

WITH upd AS (
   UPDATE coupon
   SET    used = true
   WHERE  coupon_id = 123
   AND    NOT used
   RETURNING coupon_id, other_column
   )
INSERT INTO log (coupon_id, other_column)
SELECT coupon_id, other_column FROM upd;

এটি একটি বিরল জিনিস হওয়া উচিত যা একাধিক লেনদেন একই কুপনকে ছাড়ানোর চেষ্টা করে। তাদের একটি অনন্য নম্বর আছে, তাই না? সময় একই মুহুর্তে চেষ্টা করা একাধিক লেনদেন এখনও বিরল হওয়া উচিত। (সম্ভবত কোনও অ্যাপ্লিকেশন বাগ বা কেউ কেউ গেমটি খেলার চেষ্টা করছে?)

হতে যে যেমন পারে, UPDATEশুধুমাত্র সফল ঠিক একটি লেনদেন, কোন ব্যাপার কি। একটি আপডেট করার আগে প্রতিটি লক্ষ্য সারিতে UPDATEএকটি সারি স্তরের লক অর্জন করে। যদি UPDATEএকই সারিতে সমবর্তী লেনদেন চেষ্টা করে তবে এটি সারিটির লকটি দেখতে পাবে এবং অবরুদ্ধ লেনদেন শেষ না হওয়া পর্যন্ত অপেক্ষা করবে ( ROLLBACKবা COMMIT), তারপরে লক সারিতে প্রথম হবে:

  • যদি প্রতিশ্রুতিবদ্ধ হয় তবে শর্তটি পুনরায় পরীক্ষা করুন। যদি এটি এখনও থাকে NOT usedতবে সারিটি লক করুন এবং এগিয়ে যান। অন্যটি UPDATEএখন কোনও যোগ্যতার সারি খুঁজে পায় না এবং কিছুই করে না , কোনও সারি ফিরে না আসে, সুতরাং INSERTএছাড়াও কিছুই করে না।

  • যদি ঘূর্ণায়মান হয়, সারিটি লক করুন এবং এগিয়ে যান।

নেই একটি জাতি অবস্থার জন্য কোন সম্ভাব্য

নেই একটি জন্য কোনো সম্ভাব্য অচলাবস্থা যদি না আপনি একই লেনদেনে মধ্যে আরো লিখেছেন করা বা অন্যথায় শুধু একাধিক সারি লক।

INSERTযত্ন-মুক্ত। যদি, কিছু ভুলক্রমে coupon_idইতিমধ্যে logটেবিলটিতে থাকে (এবং আপনার একটি অনন্য বা পিকে বাধা রয়েছে log.coupon_id), অনন্য লঙ্ঘনের পরে পুরো লেনদেনটি ফিরিয়ে আনা হবে। আপনার ডিবিতে একটি অবৈধ অবস্থা নির্দেশ করবে। যদি উপরের বিবৃতিটি logটেবিলে লেখার একমাত্র উপায় হয় তবে তা কখনই ঘটে না।


এটি অবশ্যই একটি বিরল জিনিস হওয়া উচিত যা একাধিক লেনদেন একই কোডটি খালাস করার চেষ্টা করে তবে আপনার সন্দেহগুলি ঠিক যে কেউ যখন সিস্টেমটি গেম করার চেষ্টা করছেন তখন এটি একচেটিয়াভাবে ঘটবে। এর জন্য অনেক ধন্যবাদ - পোস্টগ্রিসে যাওয়ার জন্য সিটিইগুলি আমার জন্য একটি বড় অঙ্কন ছিল তবে আমি বুঝতে পারি নি যে এই জন্য অন্তর্নিহিত লক করা যথেষ্ট হবে।
রব মিলার
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.