কীভাবে মাইএসকিউএলে আশাবাদী লকিং সঠিকভাবে প্রয়োগ করা যায়


13

একজন কীভাবে সঠিকভাবে মাইএসকিউএলে আশাবাদী লকিং প্রয়োগ করে?

আমাদের দলটি অনুমান করেছে যে আমাদের অবশ্যই নীচে # 4 করা উচিত অন্যথায় একটি ঝুঁকি রয়েছে যে অন্য থ্রেড রেকর্ডের একই সংস্করণটি আপডেট করতে পারে, তবে আমরা যাচাই করতে চাই যে এটি করার সর্বোত্তম উপায়।

  1. আপনি যেমন টেবিলের জন্য আশাবাদী লকিং ব্যবহার করতে চান সারণীতে একটি সংস্করণ ক্ষেত্র তৈরি করুন যেমন কলামের নাম = "সংস্করণ"
  2. নির্বাচনের সময়, সংস্করণ কলামটি অন্তর্ভুক্ত করার বিষয়টি নিশ্চিত করুন এবং সংস্করণটির নোট তৈরি করুন
  3. রেকর্ডের পরবর্তী আপডেটে, আপডেট বিবৃতিটি "যেখানে সংস্করণ = এক্স" জারি করা উচিত যেখানে এক্সটি আমাদের # 2-এ প্রাপ্ত সংস্করণ এবং X + 1 এ আপডেটের বিবৃতি চলাকালীন সংস্করণ ক্ষেত্রটি সেট করা উচিত
  4. SELECT FOR UPDATEআমরা যে রেকর্ডটি আপডেট করতে যাচ্ছি তার একটি সম্পাদন করুন যাতে আমরা সিরিয়ালাইজ করি যে আমরা যে রেকর্ডটি আপডেট করার চেষ্টা করছি তা পরিবর্তন করতে পারে।

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

আমরা সংস্করণ ক্ষেত্রগুলি / আশাবাদী লকিং ব্যবহার করেও আপডেট করার সময় আমাদের কী এই निराদবাদী লকিং করা উচিত তা ভেবে কী সঠিক?


সমস্যা কি? আপনি আপনার আপডেটের সাথে সংস্করণ নম্বরটি বাড়িয়েছেন, তারপরে দ্বিতীয় আপডেটটি ব্যর্থ হবে কারণ সংস্করণ সংখ্যাটি যখন পড়া হয়েছিল ঠিক তেমন নয় - যা আপনি চান তা।
AndreKR

আপনি নিশ্চিত? এটি অস্পষ্ট যে আপনি লেনদেনের বিচ্ছিন্নকরণের স্তরটিকে একটি নির্দিষ্ট সেটিংয়ে সেট না করে থাকেন যা আপনি অন্যান্য থ্রেডের আপডেট দেখতে পাবেন। যদি আপনি উভয় একই সময়ে লেনদেনটি প্রবেশ করেন, দ্বিতীয় থ্রেডটি আপডেট করতে গিয়ে ওল্ড ডেটাটি খুব ভাল দেখতে পারে। মাইএসকিউএল এসিআইডি অঙ্গনে ততটা শক্তিশালী নয় যেমন ওরাকল বলে, অতএব মাইএসকিউএলে আশাবাদী লকিং বাস্তবায়নের সর্বোত্তম অনুশীলনের উপায় খুঁজছেন যা নোংরা পাঠ / আপডেটগুলি প্রতিরোধ করবে।
অনুশীলন

কিন্তু তারপরে লেনদেন যেভাবেই কমিটের সময় ব্যর্থ হবে, তাই না?
AndreKR

ইঙ্গিতগুলি হ'ল
یله-

@BestPractices আপনি প্রয়োজন হয় SELECT ... FOR UPDATE , ভার্সন উভয় না সারি বা আশাবাদী লকিং। উত্তরে বিস্তারিত দেখুন।
ক্রেগ রিঞ্জার

উত্তর:


17

আপনার বিকাশকারী ভুল হয়েছে। আপনার উভয় SELECT ... FOR UPDATE বা নয় সারি সংস্করণ প্রয়োজন ।

চেষ্টা করে দেখুন। ওপেন তিন মাইএসকিউএল সেশন (A), (B)এবং (C)একই ডাটাবেসের সাথে।

ইন (C)ইস্যু:

CREATE TABLE test(
    id integer PRIMARY KEY,
    data varchar(255) not null,
    version integer not null
);
INSERT INTO test(id,data,version) VALUES (1,'fred',0);
BEGIN;
LOCK TABLES test WRITE;

উভয় ইন (A)এবং (B)ইস্যু একটি UPDATEযে পরীক্ষা এবং সেট সারি সংস্করণ, পরিবর্তন winnerপ্রতিটি টেক্সট যাতে আপনি দেখতে পারেন যা অধিবেশন যা হল:

-- In (A):

BEGIN;
UPDATE test SET data = 'winnerA',
            version = version + 1
WHERE id = 1 AND version = 0;

-- in (B):

BEGIN;
UPDATE test SET data = 'winnerB',
            version = version + 1
WHERE id = 1 AND version = 0;

এখন (C), UNLOCK TABLES;লক প্রকাশ করতে।

(A)এবং (B)সারি লক জন্য দৌড় হবে। তাদের মধ্যে একটি জিতে যাবে এবং লকটি পাবে। অন্যটি লক করে ব্লক করবে। লকটি পেয়েছে এমন বিজয়ী সারিটি পরিবর্তন করতে এগিয়ে যাবে। ধরে নেওয়া যাক (A)বিজয়ী, আপনি এখন পরিবর্তিত সারি (এখনো অন্যান্য লেনদেনের তাই দৃশ্যমান নয় Uncommitted) একটি সঙ্গে দেখতে পারেন SELECT * FROM test WHERE id = 1

এখন COMMITবিজয়ী অধিবেশন, বলুন (A)

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

পেস্টবিনে সেশন লগগুলি এখানে দেখুনmysql --prompt="A> "সেশনগুলির মধ্যে পার্থক্যটি বলা সহজ করার জন্য আমি ইত্যাদি ব্যবহার করেছি । আমি সময়ক্রম অনুসারে আউটপুটটি অনুলিপি করে কপি করেছি এবং আটকিয়েছি, সুতরাং এটি সম্পূর্ণ কাঁচা আউটপুট নয় এবং এটি অনুলিপি করে আটকানোর ক্ষেত্রে আমি ত্রুটি করতে পারতাম। এটি পরীক্ষা করে দেখুন।


আপনি যদি একটি সারি সংস্করণ ক্ষেত্র যোগ না করে থাকেন , তবে আপনার SELECT ... FOR UPDATEনির্ভরযোগ্যভাবে অর্ডার নিশ্চিত করতে সক্ষম হতে হবে।

আপনি যদি এটির বিষয়ে চিন্তা করেন তবে যদি আপনি তাত্ক্ষণিকভাবে ডেটা পুনরায় ব্যবহার না করে বা আপনি সারি সংস্করণ ব্যবহার করছেন তবে অবিলম্বে একটি করছেন যদি SELECT ... FOR UPDATEতা সম্পূর্ণরূপে বাজে । একটি লক যাহাই হউক না কেন নিতে হবে। অন্য কেউ যদি আপনার পঠন এবং পরবর্তী লেখার মধ্যে সারি আপডেট করে তবে আপনার সংস্করণ আর মেলে না তাই আপনার আপডেট ব্যর্থ হবে। আশাবাদী লকিং এইভাবে কাজ করে।UPDATESELECTUPDATE

এর উদ্দেশ্য SELECT ... FOR UPDATEহ'ল:

  • অচলাবস্থা এড়াতে লক অর্ডার পরিচালনা করতে; এবং
  • আপনি যখন কোনও সারি থেকে ডেটা পড়তে চান তার জন্য একটি সারি লকটির স্প্যান প্রসারিত করতে, অ্যাপ্লিকেশনটিতে এটি পরিবর্তন করুন এবং একটি নতুন সারি লিখুন যা মূলের উপর ভিত্তি করে SERIALIZABLEবিচ্ছিন্নতা বা সারি সংস্করণ ব্যবহার না করে লিখুন ।

আপনার কাছে আশাবাদী লকিং (সারি সংস্করণ) এবং উভয়ই ব্যবহার করার দরকার নেই SELECT ... FOR UPDATE। এক বা অন্য ব্যবহার করুন।


ধন্যবাদ ক্রেগ আপনি সঠিক ছিলেন - বিকাশকারী ভুল করেছিলেন। এই পরীক্ষা চালানোর জন্য ধন্যবাদ।
অনুশীলনগুলি

এসকিউএল সার্ভার সম্পর্কে কী? লেনদেনের বিচ্ছিন্নতা স্তরের স্বাধীনভাবে আপডেট হওয়া সারিতে সর্বদা লক অর্জিত হয়?
প্ল্লেক্স

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

@ ক্রেইগ্রিঞ্জার, বি কি কমিটের আগে তালা পেলে তবে আপডেটের পরে কী হবে?
মেংটি

1
@ মেনজিটি এটি করতে পারে না, এ কারণেই এটি একটি লক।
ক্রেগ রিঞ্জার

0
UPDATE tbl SET owner = $me,
               id = LAST_INSERT_ID(id)
    WHERE owner = ''
    LIMIT 1;
$id = SELECT LAST_INSERT_ID();
Do some stuff (arbitrarily long time)...;
UPDATE  tbl SET owner = '' WHERE id = $id;

কোনও লক প্রয়োজন (টেবিল নয়, লেনদেন নয়) বা প্রয়োজনীয়ও নয়:

  • হালনাগাদ পারমাণবিক
  • LAST_INSERT_ID () সেশন-নির্দিষ্ট, তাই থ্রেড-নিরাপদ।
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.