เมื่อเร็ว ๆ นี้แอปพลิเคชั่นทั้งสองได้รับการเปลี่ยนแปลงและมีปัญหามากมายในระหว่างกระบวนการเปิดตัว (ส่วนหนึ่งเกิดจากความเข้าใจผิดของวัตถุ)
ก่อนอื่นให้เข้าใจวัตถุ:
การประทับเวลา
ตัวเลข 4 หลักแรกคือการประทับเวลา UNIX ซึ่งเป็นหมวดหมู่ INT เราแยกตัวเลข 4 หลักแรกของ ObjectID ในตัวอย่างข้างต้น "4DF2DCEC" จากนั้นติดตั้งไว้ในเลขฐานสิบหกถึงทศนิยม: "1307761900" หมายเลขนี้คือการประทับเวลา เพื่อให้เอฟเฟกต์ชัดเจนยิ่งขึ้นเราจะแปลงการประทับเวลานี้เป็นรูปแบบเวลาที่เราคุ้นเคย (เป็นวินาที)
$ date -d '1970-01-01 UTC 1307761900 วินาที' -u
วันเสาร์ที่ 11 มิถุนายน 2554 03:11:40 UTC
4 ไบต์แรกจริงซ่อนเวลาของการสร้างเอกสารและการประทับเวลาอยู่ที่ด้านหน้าของตัวละครซึ่งหมายความว่า objectId จะถูกจัดเรียงอย่างคร่าวๆโดยการแทรกซึ่งมีบทบาทอย่างมากในบางแง่มุมเช่นการปรับปรุงประสิทธิภาพการค้นหาเป็นดัชนี ฯลฯ สิ่งนี้ยังตอบความจริงที่ว่าเมื่อเราสร้างวัตถุหลาย ๆ ตัวในลักษณะที่รวดเร็วและต่อเนื่องเราจะพบว่าตัวเลขสองสามตัวแรกไม่ค่อยพบการเปลี่ยนแปลงเพราะพวกเขาใช้เวลาปัจจุบัน ผู้ใช้หลายคนกังวลเกี่ยวกับการซิงโครไนซ์เวลาเซิร์ฟเวอร์ ในความเป็นจริงคุณค่าที่แท้จริงของการประทับเวลานี้ไม่สำคัญตราบใดที่มันเพิ่มขึ้นอย่างต่อเนื่อง
เครื่องจักร
สามไบต์ถัดไปคือ 2CDCD2 สามไบต์นี้เป็นตัวระบุที่ไม่ซ้ำกันของโฮสต์ที่ตั้งอยู่และโดยทั่วไปจะเป็นค่าแฮชของชื่อโฮสต์เครื่อง สิ่งนี้ทำให้มั่นใจได้ว่าโฮสต์ที่แตกต่างกันสร้างค่าแฮชของเครื่องที่แตกต่างกันและตรวจสอบให้แน่ใจว่าไม่มีความขัดแย้งในการแจกแจง นี่คือเหตุผลที่สตริงใน ObjectId ที่สร้างโดยเครื่องเดียวกันนั้นเหมือนกันทุกประการ
PID
เครื่องด้านบนคือเพื่อให้แน่ใจว่า objectIds ที่สร้างขึ้นบนเครื่องจักรที่แตกต่างกันไม่ขัดแย้งในขณะที่ PID คือการสร้างวัตถุที่ไม่ขัดแย้งในกระบวนการ MongoDB ที่แตกต่างกันในเครื่องเดียวกัน สองบิตถัดไปของ 0936 เป็นตัวระบุกระบวนการที่สร้างวัตถุ
การเพิ่มขึ้น
เก้าไบต์แรกให้แน่ใจว่าวัตถุที่สร้างขึ้นโดยเครื่องจักรและกระบวนการต่าง ๆ ภายในหนึ่งวินาทีไม่ขัดแย้ง สามไบต์ถัดไป A8B817 เป็นตัวนับที่เพิ่มขึ้นโดยอัตโนมัติเพื่อให้แน่ใจว่าวัตถุที่สร้างขึ้นภายในวินาทีเดียวกันไม่พบความขัดแย้งทำให้กำลัง 256 ถึง 3 เท่ากับเอกลักษณ์ของบันทึก 16777216
ความเป็นเอกลักษณ์ของวัตถุ
คุณอาจคิดว่าในระดับหนึ่งสามารถรับประกันได้ว่าจะไม่ซ้ำกันไม่ว่าจะเป็นบนไคลเอนต์หรือบนเซิร์ฟเวอร์
ความเข้าใจผิด 1. คำสั่งซื้อเอกสารสอดคล้องกับคำสั่งแทรกหรือไม่?
สถานการณ์เธรดเดี่ยว
การประทับเวลา, เครื่อง, PID และ Inc ใน ObjectId สามารถรับประกันได้ว่าจะไม่ซ้ำกันเพราะในเครื่องเดียวกันและกระบวนการเดียวกัน
มีปัญหาที่นี่การดำเนินการของ MongoDB เป็นแบบมัลติเธรด A, B, C ... เมื่อหลายเธรดดำเนินการในร้านค้าจะไม่รับประกันว่าจะเป็นอย่างใดอย่างหนึ่งก่อนหน้านี้ดังนั้นมันจะไม่เป็นระเบียบ
สถานการณ์แบบมัลติเธรดหลายเครื่องหรือหลายกระบวนการ
ลองดูที่ Mache และ PID ใน ObjectID ที่ไม่สามารถรับประกันได้ว่าจะไม่ซ้ำกัน จากนั้นข้อมูลจะไม่เป็นระเบียบมากขึ้น
สารละลาย:
เนื่องจากข้อมูลในคอลเลกชันไม่ได้ถูกเรียงลำดับ (รวมถึงคอลเลกชันที่ต่อยอด) วิธีที่ง่ายที่สุดคือการเรียงลำดับ ObjectId
มีสองวิธีในการจัดเรียง
1. คำสั่งสอบถาม MongoDB
jQuery Query = ใหม่แบบสอบถาม (); if (id! = null) {jQuery.addcriteria (criteria.where ("_ id"). gt (id)); } jQuery.with (sort. new (sort.direction.asc, "_id"));2.Java.util.PriorityQueue
ตัวเปรียบเทียบ <DbObject> comparator = new comparator <DbObject> () {@Override public int Compare (dBoBject O1, dBoBject O2) {return ((objectId) o1.get ("_ id")). compareto (objectId) o2.get ("_ id") - PriorityQueue <DbObject> queue = new PriorityQueue <DbObject> (200, ตัวเปรียบเทียบ);ความเข้าใจผิด 2: เมื่อลูกค้าหลายรายมีการเกิดขึ้นพร้อมกันสูงคำสั่งซื้อสามารถรับประกันได้ (หลังจากเรียงลำดับ) หรือไม่?
หากคุณตรวจสอบให้แน่ใจว่าการเขียนนั้นยิ่งใหญ่กว่าการอ่านค่า (มากกว่าหนึ่งวินาที) สิ่งนี้จะไม่เกิดขึ้นตามคำสั่ง
ลองดูตัวอย่างต่อไปนี้
ตอนนี้ดูรูปนำข้อมูลออกมาสองครั้ง
อันดับแรก
4DF2DCEC AAAA FFFF 36A8B813
4DF2DCEC AAAA EEEE 36A8B813
4DF2DCEC BBBB 1111 36A8B814
ครั้งที่สอง
4DF2DCEC BBBB 1111 36A8B813
4DF2DCEC AAAA FFFF 36A8B814
4DF2DCEC AAAA EEEE 36A8B814
ตอนนี้ถ้าคุณใช้ค่าสูงสุดแรก (4DF2DCEC BBBB 1111 36A8B814) เพื่อทำผลการสอบถามถัดไปมันจะพลาด
สามรายการของครั้งที่สองเนื่องจาก (4DF2DCEC BBBB 1111 36A8B814) มากกว่าบันทึกทั้งหมดที่ใช้เป็นครั้งที่สอง
สิ่งนี้จะนำไปสู่การสูญเสียข้อมูล
สารละลาย:
เนื่องจากการประทับเวลาของ ObjectID ถูกตัดออกเป็นวินาทีตัวเลขสี่หลักแรกของตัวดำเนินการตัวนับเป็นเครื่องและหมายเลขกระบวนการ
1. บันทึกกระบวนการก่อนช่วงเวลาที่กำหนด (มากกว่าหนึ่งวินาที) ดังนั้นแม้ว่าเครื่องและหมายเลขกระบวนการทำให้เกิดความผิดปกติจะไม่มีความผิดปกติก่อนช่วงเวลา
2. การแทรกจุดเดียวการดำเนินการแทรกที่ถูกแจกจ่ายไปยังหลายจุดตอนนี้ถูกสอบถามโดยจุดหนึ่งเพื่อให้แน่ใจว่าเครื่องและหมายเลขกระบวนการเหมือนกันและใช้ตัวเลือกตัวนับเพื่อทำบันทึกเป็นระเบียบ
ที่นี่เราใช้วิธีแรก
ความเข้าใจผิด 3. อย่าตั้งค่า dbobject_id โดยใช้ mongoDB เพื่อตั้งค่า ObjectId?
ในระหว่างการดำเนินการแทรก MongoDB เมื่อ DBBASICOBJECT () ใหม่ทุกคนเห็นว่า _ID ไม่ได้กรอกไว้เว้นแต่ _ID จะถูกตั้งค่าด้วยตนเอง ดังนั้นจึงตั้งค่าบนเซิร์ฟเวอร์หรือไม่?
มาดูรหัสสำหรับการดำเนินการแทรก:
คลาสการดำเนินการ
Public Writeresult Insert (รายการ <DbObject> รายการ, com.mongoDb.writeConcons ความกังวล, dbencoder encoder) {ถ้า (กังวล == null) {โยน unlegalargumentException ใหม่ ("การเขียนข้อกังวลไม่สามารถเป็นโมฆะ"); } return insert (list, true, uncoder); -คุณจะเห็นว่าคุณต้องเพิ่มค่าเริ่มต้นคือการเพิ่ม
Prefected Writeresult Insert (รายการ <DbObject> รายการบูลีนควรจะติดตั้ง com.mongoDb.writeConcern, dbencoder encoder) {ถ้า (encoder == null) encoder = defaultDbenCoder.factory.create (); if (willtrace ()) {สำหรับ (dbobject o: list) {trace ("บันทึก:" + _fullnamespace + "" + json.serialize (o)); }} if (ควรใช้) {สำหรับ (dBoBject o: list) {ใช้ (o); _CheckObject (o, false, false); Object ID = o.get ("_ id"); if (ID อินสแตนซ์ของ ObjectId) {((objectId) id) .notNew (); }}} writeresult last = null; int cur = 0; int maxsize = _mongo.getMaxBsOnObjectSize (); ในขณะที่ (cur <list.size ()) {outmessage om = Outmessage.Insert (นี่, encoder, กังวล); สำหรับ (; cur <list.size (); cur ++) {dbobject o = list.get (cur); OM.putObject (O); // ขีด จำกัด สำหรับการแทรกแบบแบทช์คือ 4 x maxbson บนเซิร์ฟเวอร์ใช้ 2 x เพื่อความปลอดภัยถ้า (om.size ()> 2 * maxsize) {cur ++; หยุดพัก; }} last = _connector.say (_db, OM, ข้อกังวล); } return ล่าสุด; -เพิ่มการดำเนินการโดยอัตโนมัติ
/** * การโทร {@link dbcollection#ใช้ (com.mongoDb.dbobject, boolean)} ด้วย ureid = true * @param o <code> dbobject </code> เพื่อเพิ่มฟิลด์ * @return วัตถุพารามิเตอร์ที่แก้ไข */วัตถุสาธารณะ }/** * การโทร {@link dbcollection#doapply (com.mongoDb.dbobject)} เลือกเพิ่มฟิลด์ _id อัตโนมัติ * @param jo วัตถุเพื่อเพิ่มฟิลด์ลงใน * @param ตรวจสอบให้แน่ใจ id = jo.get ("_id"); if (ตรวจสอบให้แน่ใจว่า && id == null) {id = objectId.get (); jo.put ("_id", id); } doapply (Jo); return id; -อย่างที่คุณเห็น ObjectId จะถูกเพิ่มลงในแพ็คเกจไดรเวอร์ MongoDB โดยอัตโนมัติ
วิธีการบันทึก
นักเขียนสาธารณะบันทึก (dbobject jo, writeConcern clusing) {ถ้า (checkreadonly (true)) ส่งคืน null; _CheckObject (Jo, False, False); Object id = jo.get ("_id"); if (id == null || (ID อินสแตนซ์ของ ObjectId && ((objectId) id) .isnew ())) {ถ้า (id! = null && id อินสแตนซ์ของ ObjectId) ((objectId) id) .notNew (); ถ้า (ข้อกังวล == null) return insert (jo); else return insert (jo, uncous); } dBoBject q = ใหม่ basicDbObject (); Q.put ("_id", id); ถ้า (ข้อกังวล == null) return update (q, jo, true, false); else return update (q, jo, true, false, กังวล); -เพื่อสรุปโดยค่าเริ่มต้น ObjectId จะถูกสร้างขึ้นโดยไคลเอนต์และไม่ใช่โดยเซิร์ฟเวอร์โดยไม่ต้องตั้งค่า
ความเข้าใจผิด 4. FindandModify สามารถรับตัวแปรอัตโนมัติได้หรือไม่?
DBOBJECT UPDATE = ใหม่ BASICDBOBJECT ("$ Inc", ใหม่ BASICDBOBJECT ("CANTER", 1)); DBOBJECT QUERY = ใหม่ BASICDBOBJECT ("_ id", คีย์); dbObject result = getMongotemplate (). getCollection (CollectionName) .FindandModify (Query, Update); if (result == null) {dBoBject doc = ใหม่ basicDbObject (); doc.put ("ตัวนับ", 1l); doc.put ("_ id", คีย์); // insert (collectionname, doc); getMongotemplate (). บันทึก (doc, collectionname); กลับ 1l; } return (long) result.get ("counter");การรับตัวแปร Autoincrement จะถูกเขียนโดยใช้วิธีนี้ แต่เราจะค้นหาหลังจากดำเนินการ
การดำเนินการ FindAndModify ก่อนที่จะดำเนินการค้นหาแล้วดำเนินการแก้ไขดังนั้นเมื่อผลลัพธ์เป็นโมฆะควรเพิ่มและส่งคืน 0
ข้างต้นคือความเข้าใจผิดและชุดของปัญหาที่เกิดจากวัตถุใน MongoDB ที่บรรณาธิการแนะนำให้คุณ ฉันหวังว่ามันจะเป็นประโยชน์กับคุณ หากคุณมีคำถามใด ๆ โปรดฝากข้อความถึงฉันและบรรณาธิการจะตอบกลับคุณทันเวลา ขอบคุณมากสำหรับการสนับสนุนเว็บไซต์ Wulin.com!