মাইএসকিউএল: ল্যান্ডিং টেবিলগুলি লেনদেন


110

লেনদেন বনাম লকিং টেবিলগুলির সাথে আমি ডাটাবেসের অখণ্ডতা নিশ্চিত করতে কিছুটা বিভ্রান্ত হয়েছি এবং নিশ্চিত করুন যে একটি নির্বাচন এবং আপডেট আপডেট সিঙ্কে রয়ে গেছে এবং অন্য কোনও সংযোগ এতে হস্তক্ষেপ করছে না। আমার দরকার:

SELECT * FROM table WHERE (...) LIMIT 1

if (condition passes) {
   // Update row I got from the select 
   UPDATE table SET column = "value" WHERE (...)

   ... other logic (including INSERT some data) ...
}

আমার নিশ্চিত করতে হবে যে অন্য কোনও ক্যোয়ারী হস্তক্ষেপ করবে না এবং এটি সম্পাদন করবে না SELECT(সংযোগটি সারিটি আপডেট করা শেষ করার আগে 'পুরানো মান' পড়ছে)।

আমি জানি LOCK TABLES tableযে একবারে 1 টি সংযোগ এটি করছে কিনা তা নিশ্চিত করতে আমি ডিফল্ট করতে পারি, এবং কাজ শেষ হয়ে গেলে এটি আনলক করতে পারি, তবে এটি ওভারকিলের মতো বলে মনে হয়। কোনও লেনদেনে এটিকে মোড়ানো কি একই কাজ করবে (অন্য কোনও সংযোগটি একই প্রক্রিয়াটি চেষ্টা করছে তা নিশ্চিত করে অন্যজন এখনও প্রক্রিয়া চলছে)? অথবা একটি SELECT ... FOR UPDATEবা SELECT ... LOCK IN SHARE MODEআরও ভাল হবে?

উত্তর:


173

সারণী লক করা অন্য ডিবি ব্যবহারকারীদের আপনার সজ্জিত সারি / সারণীগুলিকে প্রভাবিত করতে বাধা দেয়। কিন্তু লকগুলি এবং তাদের মধ্যে, এটি নিশ্চিত করবে না যে আপনার যুক্তিটি একটি সামঞ্জস্যপূর্ণ অবস্থায় এসেছে।

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

$balance = "GET BALANCE FROM your ACCOUNT";
if ($balance < $amount_being_paid) {
    charge_huge_overdraft_fees();
}
$balance = $balance - $amount_being paid;
UPDATE your ACCOUNT SET BALANCE = $balance;

$balance = "GET BALANCE FROM receiver ACCOUNT"
charge_insane_transaction_fee();
$balance = $balance + $amount_being_paid
UPDATE receiver ACCOUNT SET BALANCE = $balance

এখন, কোনও লক নেই এবং কোনও লেনদেন ছাড়াই, এই সিস্টেমটি বিভিন্ন বর্ণের অবস্থার জন্য ঝুঁকির মধ্যে রয়েছে, যার মধ্যে সবচেয়ে বড়টি হচ্ছে আপনার অ্যাকাউন্টে একাধিক অর্থ প্রদান করা হয়, বা সমান্তরালে গ্রহীতার অ্যাকাউন্টটি। আপনার কোডটিতে আপনার ভারসাম্য পুনরুদ্ধার করা হয়েছে এবং বিশাল_ওগ্রাফ্রাট_ফিজ () এবং কী করছেন না, এটি সম্পূর্ণভাবে সম্ভব যে অন্য কিছু অর্থ প্রদানের সমান্তরালে একই ধরণের কোড চলবে। তারা আপনার ভারসাম্য পুনরুদ্ধার করবে (বলুন, $ 100), তাদের লেনদেন করুন (আপনি যে 20 ডলার দিচ্ছেন এবং যে 30 ডলার আপনাকে দিয়ে দিচ্ছেন) তা বের করুন) এবং এখন উভয় কোড পাথের দুটি পৃথক ব্যালেন্স রয়েছে: $ 80 এবং $ 70। কোনটি শেষ হয় তার উপর নির্ভর করে, আপনার অ্যাকাউন্টে এই দুটি ব্যালেন্সের মধ্যে কোনওটি শেষ হবে, 50 এর পরিবর্তে আপনার উচিত হবে ($ 100 - $ 20 - $ 30)। এই ক্ষেত্রে, "আপনার পক্ষে ব্যাংক ত্রুটি"

এখন, ধরুন আপনি লক ব্যবহার করেন। আপনার বিলের অর্থ প্রদান (20 ডলার) প্রথমে পাইপটিকে আঘাত করে, সুতরাং এটি আপনার অ্যাকাউন্টের রেকর্ডটি জয় করে এবং লক করে। এখন আপনি একচেটিয়া ব্যবহার পেয়েছেন এবং ভারসাম্য থেকে ২০ ডলার কেটে নিতে পারবেন এবং নতুন ব্যালেন্সটি শান্তিতে আবার লিখতে পারবেন ... এবং আপনার অ্যাকাউন্টটি প্রত্যাশার সাথে $ 80 দিয়ে শেষ হবে। তবে ... আহো ... আপনি প্রাপকের অ্যাকাউন্ট আপডেট করার চেষ্টা করুন, এবং এটি লক হয়ে গেছে, এবং কোডের অনুমতি ছাড়াই লক হয়ে গেছে, আপনার লেনদেনের সময় নির্ধারণ করছে ... আমরা বোকা ব্যাংকগুলির সাথে ডিল করছি, তাই সঠিক ত্রুটির পরিবর্তে হ্যান্ডলিং, কোডটি কেবল একটি টানে exit()এবং আপনার 20 ডলার ইলেক্ট্রনগুলির একটি ঘুষিতে পরিণত হয়। এখন আপনি 20 ডলার আউট করেছেন এবং এখনও আপনি রিসিভারের কাছে 20 ডলার andণী রয়েছেন এবং আপনার টেলিফোনটি পুনরায় জমা দেওয়া হবে।

সুতরাং ... লেনদেন প্রবেশ করুন আপনি একটি লেনদেন শুরু করেন, আপনি আপনার অ্যাকাউন্টে $ 20 ডেবিট করেন, আপনি রিসিভারকে $ 20 দিয়ে ক্রেডিট করার চেষ্টা করেন ... এবং আবার কিছু ফুটে উঠেছে। তবে এবার পরিবর্তে exit()কোডটি কেবলমাত্র করতে পারে rollback, এবং poof, আপনার $ 20 ম্যাজিকভাবে আপনার অ্যাকাউন্টে ফিরে যুক্ত হবে added

শেষ অবধি, এটি এখানে সিদ্ধ হয়:

লকগুলি আপনার সাথে যে কোনও ডাটাবেস রেকর্ডের সাথে হস্তক্ষেপ করা থেকে বিরত রাখে। লেনদেনগুলি আপনার "পূর্বে" জিনিসগুলিতে হস্তক্ষেপ থেকে কোনও "পরে" ত্রুটি রাখে। কোনও একাই গ্যারান্টি দিতে পারে না যে শেষ পর্যন্ত জিনিসগুলি ঠিক কাজ করে। তবে একসাথে তারা করে।

আগামীকালের পাঠে: ডেডলকের জয়।


4
আমিও / এখনও বিভ্রান্ত বলুন যে রিসিভার অ্যাকাউন্টটি শুরু করার জন্য এতে 100 ডলার ছিল এবং আমরা আমাদের অ্যাকাউন্ট থেকে 20 ডলার বিলের পেমেন্ট যুক্ত করছি। লেনদেনের বিষয়ে আমার বোঝা হ'ল তারা যখন শুরু করেন, কোনও লেনদেনের শুরুতে যে কোনও ইন-লেনদেন অপারেশন সেই ডেটাবেস দেখতে পায়। যেমন: যতক্ষণ না আমরা এটি পরিবর্তন করি, রিসিভার অ্যাকাউন্টে 100 ডলার থাকে। সুতরাং ... আমরা যখন 20 ডলার যুক্ত করি তখন আমরা আসলে $ 120 এর ব্যালেন্স সেট করি। তবে আমাদের লেনদেনের সময়, কেউ যদি রিসিভার অ্যাকাউন্টটি 0 ডলারে ফেলে দেয় তবে কী হবে? এটি কি কোনওভাবে প্রতিরোধ করা হচ্ছে? তারা কি আবার যাদুতে আবার $ 120 পাবে? এই কারণেই লকগুলিও দরকার হয়?
রাশ

হ্যাঁ, সেখানেই তালাবন্ধি খেলতে আসে। একটি সঠিক ব্যবস্থা রেকর্ডটি লিপ-লক করে রাখে যাতে লেনদেনের অগ্রগতি চলাকালীন অন্য কেউ রেকর্ডটি আপডেট করতে না পারে। একটি প্যারানয়েড সিস্টেম রেকর্ডটিতে একটি শর্তহীন লক রাখে যাতে কেউ "বাসি" ভারসাম্যটি পড়তে না পারে।
মার্ক বি

1
মূলত আপনার কোড পাথের ভিতরে জিনিসগুলি সুরক্ষিত হিসাবে লেনদেনগুলি দেখুন look "সমান্তরাল" কোড পাথগুলিতে সুরক্ষিত জিনিসগুলি লক করে। অচলাবস্থাগুলি আঘাত না করা পর্যন্ত ...
মার্ক বি বি

1
@ মার্কবি, সুতরাং যদি লেনদেনের একা ইতিমধ্যে গ্যারান্টি দেওয়া হয় তবে আমাদের কেন স্পষ্টভাবে লকিং করতে হবে? এমনকি এমন কোনও মামলাও হতে পারে যার মাধ্যমে আমাদের অবশ্যই স্পষ্ট লকিং করতে হবে কারণ লেনদেন একা অপ্রতুল?
পেসারিয়ার

2
এই উত্তরটি সঠিক নয় এবং ভুল সিদ্ধান্তে ডেকে আনতে পারে। এই বিবৃতি: "লকগুলি আপনার সাথে যে কোনও ডাটাবেস রেকর্ডে হস্তক্ষেপ থেকে বিরত থাকে Trans শেষ। কিন্তু একসাথে, তারা। " - আপনি বহিস্কার পেতে হবে, এটা অত্যন্ত ভুল এবং নির্বোধ নিবন্ধগুলি দেখতে হল: en.wikipedia.org/wiki/ACID , en.wikipedia.org/wiki/Isolation_(database_systems) এবং dev.mysql.com/doc/refman/5.1/ এন /…
নিকোলা স্বিতলিকা

14

আপনি কোনও লেনদেনের ভিতরে SELECT ... FOR UPDATEবা তার মধ্যে চান SELECT ... LOCK IN SHARE MODE, যেমনটি আপনি বলেছেন, যেহেতু সাধারণত SELECTs হয়, তারা লেনদেনে থাকুক বা না থাকুক, কোনও টেবিল লক করবে না। আপনি কোনটি বেছে নেবেন তা নির্ভর করে আপনার লেনদেন চলাকালীন আপনি অন্যান্য লেনদেনগুলি সেই সারিটি পড়তে সক্ষম হন কিনা তার উপর নির্ভর করে।

http://dev.mysql.com/doc/refman/5.0/en/innodb-locking-reads.html

START TRANSACTION WITH CONSISTENT SNAPSHOTআপনার জন্য কৌশলটি করবে না, কারণ অন্যান্য লেনদেনগুলি এখনও আসতে পারে এবং সেই সারিটি সংশোধন করতে পারে। নীচের লিঙ্কের ঠিক উপরে এটি উল্লেখ করা হয়েছে।

যদি অন্য সেশনগুলি একই সাথে একই টেবিলটি আপডেট করে [...] আপনি টেবিলটি এমন একটি অবস্থায় দেখতে পাবেন যা ডেটাবেজে কখনও উপস্থিত ছিল না।

http://dev.mysql.com/doc/refman/5.0/en/innodb-consistent-read.html


7

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


এটি সঠিক উত্তর হওয়া উচিত। লক করা জাতি প্রতিরোধের পরিস্থিতি প্রতিরোধের জন্য, এবং লেনদেন নির্ভরশীল ডেটা সহ একাধিক টেবিল আপডেট করার জন্য। দুটি সম্পূর্ণ ভিন্ন ধারণা, তবুও লেনদেন লক ব্যবহার করে।
নীল জল

6

একাধিক থ্রেড একই টেবিলটি আপডেট করার সময় যখন চেষ্টা করছিল IF NOT EXISTS ...এবং তারপরে এমন একটি ঘটনা INSERTঘটায় তখন আমার একইরকম সমস্যা হয়েছিল।

আমি এখানে সমস্যার সমাধান খুঁজে পেয়েছি: মানক এসকিউএল-তে কী কী কী কী লিখবেন লিখুন S

আমি বুঝতে পারি এটি সরাসরি আপনার প্রশ্নের উত্তর দেয় না তবে একক বিবৃতি হিসাবে একটি চেক এবং সন্নিবেশ করানোর একই নীতিটি খুব কার্যকর; আপনার আপডেট সম্পাদন করার জন্য আপনার এটি পরিবর্তন করতে সক্ষম হওয়া উচিত।


2

আপনি লক এবং লেনদেনের সাথে বিভ্রান্ত তারা আরএমডিবিতে দুটি ভিন্ন জিনিস। লক ডেটা বিচ্ছিন্নকরণের উপর ফোকাস করার সময় সাম্প্রতিক ক্রিয়াকলাপগুলিকে বাধা দেয়। পরীক্ষা করে দেখুন এই শোধন এবং কিছু সুতনু সমাধান জন্য মহান নিবন্ধ।


1
আপনার সাথে কাজ করা রেকর্ডগুলিতে হস্তক্ষেপ করা থেকে লকগুলি অন্যকে বাধা দেয় যা এটি সংক্ষিপ্তভাবে করে তা বর্ণনা করে এবং লেনদেনগুলি পরে ত্রুটিগুলি (সমান্তরালভাবে পরিবর্তিত হওয়া অন্যদের) আপনার পূর্ববর্তী কাজগুলিতে হস্তক্ষেপ থেকে বাধা দেয় (ইভেন্টে রোলব্যাকের মাধ্যমে কেউ কিছু করেছে সমান্তরালভাবে) বেশিরভাগ লেনদেনের পরিমাণ দাঁড়ায় ... এই বিষয়গুলি সম্পর্কে তাঁর উপলব্ধি সম্পর্কে কি বিভ্রান্তি রয়েছে?
স্টিভিসাম

1

আমি একটি ব্যবহার করব

START TRANSACTION WITH CONSISTENT SNAPSHOT;

শুরু করার জন্য, এবং ক

COMMIT;

সঙ্গে শেষ।

আপনার স্টোরেজ ইঞ্জিন যদি লেনদেনকে সমর্থন করে (তবে ইনোডিবি) তবে আপনার ডাটাবেসের অন্য ব্যবহারকারীদের থেকে আপনি যে কোনও কিছু করতে পারেন ।


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

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

1
@ রায়ান এটি কোনও লক করে না; আপনি সঠিক. লকিং (বা না) আপনি যে ধরণের ক্রিয়াকলাপ করেন তা দ্বারা নির্ধারিত হয় (নির্বাচন / আপডেট / ডিলিট)।
অ্যালিসন আর।

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