في صيف 2018 (أي الآن ، حتى وقت كتابة هذا التقرير) ، حدث ما لا يصدق - تم إدخال معاملات ACID الصادقة إلى MongoDB . مع إصدار الإصدار الرابع من نظام إدارة قواعد البيانات المستند إلى المستندات ، يمكن استخدامه للتطبيقات الأكثر خطورة قليلاً.
لأولئك الذين هم في الخزان ، باختصار: تسمح لنا المعاملات بإجراء سلسلة من التغييرات في العديد من المستندات وحفظها في وقت واحد ، أو أيضًا إلغاء جميع التغييرات التي تم إجراؤها داخل المعاملة بنفس الطريقة ، إذا حدث خطأ ما ، أو تعطل التطبيق .
لسوء الحظ ، المطور ليس من السهل استخدام هذه الميزة الفائقة. أدناه سأخبرك لماذا ، وماذا تفعل حيال ذلك كله.
إذا فتحنا وثائق نظام إدارة قواعد البيانات (DBMS) في قسم المعاملات ، فيمكننا رؤية الملاحظة التالية:
المعاملات متعددة المستندات متاحة لمجموعات النسخ المتماثلة فقط. تتم جدولة معاملات التجمعات الحادة في MongoDB 4.2
هذا يخبرنا أن خادم MongoDB البسيط لا يدعم المعاملات ، فقط كتلة في وضع مجموعة النسخ المتماثلة . سيأتي دعم المجموعات الحادة أيضًا لاحقًا في الإصدار 4.2.
في الوقت نفسه ، سيسمح لنا الخادم العادي ببدء معاملة أو حفظها أو إلغائها ، ولكن لا يمكن فعل أي شيء داخلها ، سيتم عرض خطأ مثل هذا:
WriteCommandError({ : 0, : , : 20, : })
لحسن الحظ ، يمكن لأي شخص تشغيل كتلة MongoDB خادم واحد. على أجهزتي ، التي أعمل عليها في التطوير ، أقوم بتشغيل جميع DBMSs في حاويات عامل ميناء . على سبيل المثال ، يبدو بدء خادم MongoDB عادي كما يلي:
docker run -v ~/mongo/:/data/db --name mongo --restart=always -p 27017:27017 -d mongo mongod --smallfiles
دعنا نحلل مفاتيح بدء التشغيل:
- -v ~ / mongo /: / data / db يعني تحميل الدليل المحلي ~ / mongo / in / data / db للحاوية ، لذلك سيتم تخزين قاعدة البيانات نفسها على الجهاز المضيف ، مما سيسمح لنا بحذف الحاوية قيد التشغيل ، وتحديث الإصدارات ، وما إلى ذلك. د. مع الحفاظ على بياناتنا ؛
- - الاسم mongo يحدد اسم الحاوية ؛
- --restart = يقول دائمًا أنه في حالة تعطل الخدمة في الحاوية ، يجب إعادة تشغيلها ، وكذلك بدء الحاوية بعد تحميل نظام التشغيل ؛
- -p 27017: 27017 "إعادة توجيه" المنفذ إلى الجهاز المضيف ؛
- يشير -d إلى أنك بحاجة إلى بدء الحاوية كبرنامج خفي ؛
- mongo - اسم الصورة لتشغيل الحاوية ؛
- mongod --smallfiles - الأمر لبدء الخدمة في الحاوية.
كيفية بدء تشغيل خادم بسيط ، أحضرت فقط كمرجع. الآن دعونا نفهم ما يجب القيام به لبدء خادم يدعم المعاملات.
بادئ ذي بدء ، يجب عليك إنشاء شبكة جديدة داخل عامل الميناء ، حيث ستعمل جميع خوادم مجموعتنا. نعم ، لقد كتبت أعلاه أنه سيكون هناك خادم واحد ، ولكن يجب إنشاء شبكة ، وإلا فلن يعمل شيء.
docker network create mongo-cluster
بعد ذلك ، في معلمات تشغيل الحاوية ، تحتاج إلى تحديد استخدام الشبكة الجديدة - net mongo-الكتلة ، وكذلك تمرير المعلمة إلى الخادم للعمل في وضع مجموعة النسخ المتماثلة: --replSet rs0 . أيضا ، حذفت عمدا التبديل --restart = دائما ، كما لا أستخدم MongoDB دائمًا في العمل في الوقت الحالي ولا أريد أن يبدأ نظام التشغيل.
docker run -v ~/mongo/:/data/db --name mongo -p 27017:27017 -d mongo mongod --smallfiles --replSet rs0
رائع ، الحاوية تعمل ، كما يمكننا رؤيتها من خلال تشغيل الأمر docker ps ورؤية شيء مثل ما يلي:
docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 2292d7e0778b mongo "docker-entrypoint.s…" About a minute ago Up About a minute 0.0.0.0:27017->27017/tcp mongo
بعد ذلك ، نحتاج إلى تهيئة المجموعة ، لهذا نذهب إلى وحدة التحكم الخاصة بالخادم الجاري تشغيله ، وننشئ تكوين المجموعة وننفذ التهيئة:
docker exec -it mongo mongo
انتهى! لقد حصلنا على كتلة من خادم MongoDB واحد. الآن يمكنك التحقق من أن كل شيء يعمل كما هو متوقع.
rs0:PRIMARY> session = db.getMongo().startSession() session { "id" : UUID("7eb81006-983f-4398-adc7-5ed23e027377") } rs0:PRIMARY> database = session.getDatabase("test") test rs0:PRIMARY> // rs0:PRIMARY> database.col.insert({name: "1"}) WriteResult({ "nInserted" : 1 }) rs0:PRIMARY> database.col.insert({name: "2"}) WriteResult({ "nInserted" : 1 }) rs0:PRIMARY> database.col.insert({name: "3"}) WriteResult({ "nInserted" : 1 }) rs0:PRIMARY> database.col.insert({name: "4"}) WriteResult({ "nInserted" : 1 }) rs0:PRIMARY> // , rs0:PRIMARY> database.col.find({}) { "_id" : ObjectId("5b45026edc396f534f11952f"), "name" : "1" } { "_id" : ObjectId("5b450272dc396f534f119530"), "name" : "2" } { "_id" : ObjectId("5b450274dc396f534f119531"), "name" : "3" } { "_id" : ObjectId("5b450276dc396f534f119532"), "name" : "4" } rs0:PRIMARY> // rs0:PRIMARY> session.startTransaction() rs0:PRIMARY> // rs0:PRIMARY> database.col.update({name: "4"}, {name: "44"}) WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 }) rs0:PRIMARY> // rs0:PRIMARY> database.col.find({}) { "_id" : ObjectId("5b45026edc396f534f11952f"), "name" : "1" } { "_id" : ObjectId("5b450272dc396f534f119530"), "name" : "2" } { "_id" : ObjectId("5b450274dc396f534f119531"), "name" : "3" } { "_id" : ObjectId("5b450276dc396f534f119532"), "name" : "44" } rs0:PRIMARY> // , -: rs0:PRIMARY> // { "_id" : ObjectId("5b450276dc396f534f119532"), "name" : "4" } rs0:PRIMARY> // rs0:PRIMARY> session.commitTransaction() rs0:PRIMARY> // rs0:PRIMARY> database.col.find({}) { "_id" : ObjectId("5b45026edc396f534f11952f"), "name" : "1" } { "_id" : ObjectId("5b450272dc396f534f119530"), "name" : "2" } { "_id" : ObjectId("5b450274dc396f534f119531"), "name" : "3" } { "_id" : ObjectId("5b450276dc396f534f119532"), "name" : "44" } rs0:PRIMARY> // rs0:PRIMARY> session.startTransaction() rs0:PRIMARY> database.col.update({name: "44"}, {name: "42"}) WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 }) rs0:PRIMARY> database.col.find({}) { "_id" : ObjectId("5b45026edc396f534f11952f"), "name" : "1" } { "_id" : ObjectId("5b450272dc396f534f119530"), "name" : "2" } { "_id" : ObjectId("5b450274dc396f534f119531"), "name" : "3" } { "_id" : ObjectId("5b450276dc396f534f119532"), "name" : "42" } rs0:PRIMARY> database.col.update({name: "1"}, {name: "21"}) WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 }) rs0:PRIMARY> database.col.find({}) { "_id" : ObjectId("5b45026edc396f534f11952f"), "name" : "21" } { "_id" : ObjectId("5b450272dc396f534f119530"), "name" : "2" } { "_id" : ObjectId("5b450274dc396f534f119531"), "name" : "3" } { "_id" : ObjectId("5b450276dc396f534f119532"), "name" : "42" } rs0:PRIMARY> session.commitTransaction() rs0:PRIMARY> // rs0:PRIMARY> database.col.find({}) { "_id" : ObjectId("5b45026edc396f534f11952f"), "name" : "21" } { "_id" : ObjectId("5b450272dc396f534f119530"), "name" : "2" } { "_id" : ObjectId("5b450274dc396f534f119531"), "name" : "3" } { "_id" : ObjectId("5b450276dc396f534f119532"), "name" : "42" } rs0:PRIMARY> // , rs0:PRIMARY> session.startTransaction() rs0:PRIMARY> database.col.update({name: "21"}, {name: "1"}) WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 }) rs0:PRIMARY> database.col.find({}) { "_id" : ObjectId("5b45026edc396f534f11952f"), "name" : "1" } { "_id" : ObjectId("5b450272dc396f534f119530"), "name" : "2" } { "_id" : ObjectId("5b450274dc396f534f119531"), "name" : "3" } { "_id" : ObjectId("5b450276dc396f534f119532"), "name" : "42" } rs0:PRIMARY> // rs0:PRIMARY> session.abortTransaction() rs0:PRIMARY> database.col.find({}) { "_id" : ObjectId("5b45026edc396f534f11952f"), "name" : "21" } { "_id" : ObjectId("5b450272dc396f534f119530"), "name" : "2" } { "_id" : ObjectId("5b450274dc396f534f119531"), "name" : "3" } { "_id" : ObjectId("5b450276dc396f534f119532"), "name" : "42" } rs0:PRIMARY> // ! ! rs0:PRIMARY>
وبالتالي ، بدون إجهاد ، يمكنك تجربة معاملات مونغ الآن دون بدء مجموعة متعددة الخوادم. أنصحك بالاطلاع على الوثائق وقراءة قيود المعاملات. على سبيل المثال ، تلك المعاملات "مباشرة" لمدة لا تزيد عن دقيقة واحدة ، إذا لم تتمكن من حفظ التغييرات ، فسيتم إلغاؤها.
ملاحظة: الغرض من هذه المقالة ليس لتعليمك كيفية استخدام عامل الميناء أو العمل مع monga ، ولكن فقط طريقة سريعة لتجربة أدوات جديدة من DBMS المثير للاهتمام.