Baru -baru ini, dua aplikasi diubah, dan serangkaian masalah terjadi selama proses peluncuran (bagian yang disebabkan oleh kesalahpahaman objektif)
Pertama -tama mari kita pahami ObjectId:
Cap waktu
4 digit pertama adalah cap waktu UNIX, kategori int. Kami mengekstrak 4 digit pertama dari ObjectId dalam contoh di atas "4DF2DCEC", dan kemudian menginstalnya dalam heksadesimal ke desimal: "1307761900". Nomor ini adalah cap waktu. Untuk membuat efek lebih jelas, kami mengonversi cap waktu ini menjadi format waktu yang biasa kami lakukan (tepat ke detik)
$ Date -D '1970-01-01 UTC 1307761900 SEC' -U
Sabtu, 11 Juni 2011 03:11:40 UTC
4 byte pertama sebenarnya menyembunyikan waktu pembuatan dokumen, dan cap waktu berada di bagian depan karakter, yang berarti bahwa ObjectId akan secara kasar diurutkan berdasarkan penyisipan, yang memainkan peran besar dalam beberapa aspek, seperti meningkatkan efisiensi pencarian sebagai indeks, dll. Keuntungan lain dari cap waktu adalah bahwa beberapa driver klien dapat parse keluar ketika catatan dimasukkan melalui objek. Ini juga menjawab kenyataan bahwa ketika kita membuat banyak ObjectIds secara cepat dan berkelanjutan, kita akan menemukan bahwa beberapa digit pertama jarang menemukan perubahan, karena mereka menggunakan waktu saat ini. Banyak pengguna khawatir menyinkronkan waktu server. Faktanya, nilai sebenarnya dari cap waktu ini tidak penting, asalkan terus meningkat.
Mesin
Tiga byte berikutnya adalah 2CDCD2. Ketiga byte ini adalah pengidentifikasi unik dari host tempat mereka berada, dan umumnya nilai hash dari nama host mesin. Ini memastikan bahwa host yang berbeda menghasilkan nilai hash mesin yang berbeda dan memastikan bahwa tidak ada konflik dalam distribusi. Inilah sebabnya mengapa string dalam ObjectID yang dihasilkan oleh mesin yang sama persis sama.
pid
Mesin di atas adalah untuk memastikan bahwa ObjectIds yang dihasilkan pada mesin yang berbeda tidak bertentangan, sedangkan PID adalah untuk menghasilkan objek yang tidak bertentangan dalam proses MongoDB yang berbeda pada mesin yang sama. Dua bit berikutnya dari 0936 adalah pengidentifikasi proses yang menghasilkan objek.
Kenaikan
Sembilan byte pertama memastikan bahwa objek yang dihasilkan oleh mesin dan proses yang berbeda dalam satu detik tidak bertentangan. Tiga byte berikutnya A8B817 adalah penghitung yang ditingkatkan secara otomatis untuk memastikan bahwa objek yang dihasilkan dalam detik yang sama tidak menemukan konflik, memungkinkan daya 256 hingga 3 sama dengan keunikan catatan 16777216.
Keunikan ObjectID
Anda mungkin berpikir bahwa sampai batas tertentu, itu dapat dijamin unik, baik pada klien atau di server.
Kesalahpahaman 1. Apakah pesanan dokumen konsisten dengan urutan penyisipan?
Situasi berulir tunggal
Timestamp, mesin, PID, dan Inc di ObjectID dapat dijamin unik karena pada mesin yang sama dan proses yang sama.
Ada masalah di sini, operasi MongoDB adalah multi-threaded. A, B, C ... Ketika beberapa utas melakukan operasi di dalam toko, tidak dijamin mana yang bisa di hadapan yang lain, jadi itu akan rusak.
Situasi multithreaded, multi-mesin atau multi-proses
Mari kita lihat mache dan pid di ObjectId yang tidak dapat dijamin unik. Maka data akan lebih rusak.
Larutan:
Karena data dalam koleksi tidak berurutan (termasuk pengumpulan capped), cara termudah adalah dengan mengurutkan objectId.
Ada dua cara untuk mengurutkan,
1. Pernyataan kueri MongoDB
query jQuery = kueri baru (); if (id! = null) {jQuery.addcriteria (kriteria.where ("_ id"). gt (id)); } jQuery.with (sort baru (sort.direction.asc, "_id"));2.java.util.priorityqueue
Komparator <DBObject> comparator = pembanding baru <DBObject> () {@Override Public int Compare (DBObject O1, DBObject O2) {return ((ObjectId) o1.get ("_ id")). CompareTo ((ObjectId) o2.get ("_ id")); }}; Prioritasqueue <DBObject> Queue = prioritas baru <dbobject> (200, pembanding);Kesalahpahaman 2: Ketika banyak klien memiliki konkurensi tinggi, dapatkah pesanan dijamin (setelah diurutkan)?
Jika Anda selalu memastikan bahwa penulisannya jauh lebih besar dari pembacaan (lebih dari satu interval kedua), ini tidak akan pernah terjadi.
Mari kita lihat contoh berikut
Sekarang lihat gambarnya, keluarkan data dua kali
Pertama
4DF2DCEC AAAA FFFF 36A8B813
4DF2DCEC AAAA EEEE 36A8B813
4DF2DCEC BBBB 1111 36A8B814
Kedua kalinya
4DF2DCEC BBBB 1111 36A8B813
4DF2DCEC AAAA FFFF 36A8B814
4DF2DCEC AAAA EEEE 36A8B814
Sekarang jika Anda mengambil nilai maksimum pertama (4DF2DCEC BBBB 1111 36A8B814) untuk melakukan hasil kueri berikutnya, maka itu akan dilewatkan
Tiga item dari kedua kalinya, karena (4DF2DCEC BBBB 1111 36A8B814) lebih besar dari semua catatan yang diambil untuk kedua kalinya.
Ini akan menyebabkan kehilangan data.
Larutan:
Karena cap waktu ObjectID dipotong menjadi detik, empat digit pertama operator penghitung adalah mesin dan nomor proses.
1. Catatan proses sebelum interval waktu tertentu (lebih dari satu detik), sehingga bahkan jika mesin dan angka proses menyebabkan gangguan, tidak akan ada gangguan sebelum interval.
2. Penyisipan titik tunggal, operasi penyisipan yang awalnya didistribusikan ke beberapa titik, sekarang ditanyai dengan satu titik untuk memastikan bahwa mesin dan nomor prosesnya sama, dan operator penghitung digunakan untuk membuat catatan secara tertib.
Di sini, kami menggunakan metode pertama.
Kesalahpahaman 3. Jangan atur dbobject_id menggunakan MongoDB untuk mengatur ObjectId?
Selama operasi penyisipan MongoDB, ketika dbbasicObject baru (), semua orang melihat bahwa _id tidak diisi, kecuali _id diatur secara manual. Jadi apakah itu diatur di server?
Mari kita lihat kode untuk operasi penyisipan:
Kelas Implementasi
Public WriterSult Insert (Daftar <DbObject> Daftar, com.mongodb.writeconcern CREACT, DBENCODER ENCODER) {if (CREACT == NULL) {Throw new IllegalArargumentException ("Write Concern tidak bisa nol"); } return insert (daftar, true, concern, encoder); }Anda dapat melihat bahwa Anda perlu menambahkan, defaultnya adalah untuk ditambahkan
Insert WriterSult yang Dilindungi (Daftar <DBObject> Daftar, Boolean harus melamar, com.mongoDb.writeconcern CREATTER, DBENCODER ENCODER) {if (encoder == null) encoder = defaultDbencoder.factory.create (); if (willtrace ()) {for (dbObject o: list) {trace ("save:" + _fullnamespace + "" + json.serialize (o)); }} if (seharusnya apply) {for (dbObject o: list) {apply (o); _CheckObject (o, false, false); Objek id = o.get ("_ id"); if (ID instanceof ObjectId) {((ObjectId) id) .notnew (); }}} WriterSult terakhir = null; int cur = 0; int maxsize = _mongo.getmaxbsonObjectSize (); while (cur <list.size ()) {outmessage om = outmessage.insert (ini, encoder, perhatian); untuk (; cur <list.size (); cur ++) {dbObject o = list.get (cur); om.putObject (o); // Batas untuk insert batch adalah 4 x maxbson di server, gunakan 2 x untuk aman jika (om.size ()> 2 * maxSize) {cur ++; merusak; }} last = _connector.say (_db, om, kekhawatiran); } return terakhir; }Secara otomatis menambahkan operasi ObjectID
/** * Panggilan {@link dbcollection#apply (com.mongodb.dbobject, boolean)} dengan pasteid = true * @param o <code> dbobject </code> yang untuk menambahkan bidang * @return objek parameter yang dimodifikasi */objek publik berlaku (dbobject o) {o, o, true, true); }/** * Panggilan {@link dbcollection#doPly (com.mongoDb.dbobject)}, secara opsional menambahkan bidang _id otomatis * @param jo objek untuk menambahkan bidang ke * @param memastikan apakah akan menambahkan </code> _ID </code> bidang * @return objek yang dimodifikasi <code> o </code/_id </code> Field * @return Objek yang dimodifikasi <code> o </code/_id </code> Field * @return Objek yang dimodifikasi <code> o </code </id * id = jo.get ("_id"); if (pasteid && id == null) {id = ObjectId.get (); jo.put ("_id", id); } DoApply (Jo); Return ID; }Seperti yang Anda lihat, ObjectID akan ditambahkan secara otomatis ke paket driver MongoDB.
Metode menabung
Public WriterSult Save (DBObject Jo, WriteConcern Concern) {if (checkReadOnly (true)) return null; _CheckObject (jo, false, false); Objek id = jo.get ("_id"); if (id == null || (ID instanceof ObjectId && ((ObjectId) ID) .IsNew ())) {if (id! = null && ID instance dari ObjectId) ((ObjectId) id) .notnew (); if (concern == null) return insert (jo); lain return insert (jo, concern); } DBObject q = new BasicDbObject (); q.put ("_id", id); if (concern == null) pembaruan pengembalian (q, jo, true, false); lain pembaruan return (q, jo, true, false, concern); }Singkatnya, secara default, ObjectId dihasilkan oleh klien dan bukan oleh server tanpa pengaturan.
Kesalahpahaman 4. Dapat FindAndModify benar-benar mendapatkan variabel kenaikan otomatis?
DBObject Update = new BasicDBObject ("$ inc", new BasicDBObject ("counter", 1)); DBObject Query = new BasicDBObject ("_ id", key); DBObject hasil = getMongoTemplate (). GetCollection (collectionName) .findandmodify (kueri, pembaruan); if (result == null) {dBObject doc = new BasicDbObject (); doc.put ("counter", 1L); doc.put ("_ id", kunci); // masukkan (collectionName, doc); getMongoTemplate (). save (doc, collectionName); kembali 1L; } return (long) result.get ("counter");Mendapatkan variabel autoINCREMEN akan ditulis menggunakan metode ini, tetapi kami akan mencari tahu setelah eksekusi.
findAndmodify operasi, pertama -tama jalankan temukan dan kemudian jalankan modifikasi, jadi ketika hasilnya nol, itu harus ditambahkan dan dikembalikan 0
Di atas adalah kesalahpahaman dan serangkaian masalah yang disebabkan oleh ObjectID di MongoDB yang diperkenalkan oleh editor kepada Anda. Saya harap ini akan membantu Anda. Jika Anda memiliki pertanyaan, silakan tinggalkan saya pesan dan editor akan membalas Anda tepat waktu. Terima kasih banyak atas dukungan Anda ke situs web Wulin.com!