최근에 두 응용 프로그램이 변형되었고 발사 과정에서 일련의 문제가 발생했습니다 (그 중 일부는 객관적인 오해로 인해 발생했습니다)
먼저 대상을 이해해 봅시다 :
타임 스탬프
처음 4 자리는 int 카테고리 인 Unix 타임 스탬프입니다. 위의 예 "4DF2DCEC"에서 ObjectID의 첫 4 자리를 추출한 다음 166 진수에서 "1307761900"으로 설치합니다. 이 숫자는 타임 스탬프입니다. 효과를보다 명확하게하기 위해이 타임 스탬프를 우리가 사용하는 시간 형식으로 변환합니다 (정확히 초)
$ DATE -D '1970-01-01 UTC 1307761900 SEC'-U
2011 년 6 월 11 일 토요일 03:11:40 UTC
처음 4 바이트는 실제로 문서 작성 시간을 숨기고 타임 스탬프는 캐릭터의 전면에 있습니다. 즉, 객체는 삽입에 의해 대략적으로 분류 될 것이며, 이는 타임 스탬프를 사용하는 것과 같은 일부 측면에서 큰 역할을하는 것과 같은 일부 측면에서 큰 역할을합니다. 이것은 또한 빠르고 연속적인 방식으로 여러 객체를 만들 때 처음 몇 자릿수가 현재 시간을 사용하기 때문에 거의 변경 사항을 찾지 못한다는 사실을 알게됩니다. 많은 사용자들이 서버 시간 동기화에 대해 걱정하고 있습니다. 실제로,이 타임 스탬프의 실제 가치는 지속적으로 증가하는 한 중요하지 않습니다.
기계
다음 3 바이트는 2CDCD2입니다. 이 3 바이트는 호스트가 위치한 호스트의 고유 식별자이며 일반적으로 기계 호스트 이름의 해시 값입니다. 이를 통해 다른 호스트가 다른 기계 해시 값을 생성하고 분포에 충돌이 없도록합니다. 그렇기 때문에 같은 기계로 생성 된 객관적인 문자열이 정확히 동일합니다.
PID
위의 기계는 다른 기계에서 생성 된 대상이 충돌하지 않도록하는 것이며, PID는 동일한 기계의 다른 MongoDB 프로세스에서 충돌하지 않는 객체를 생성하는 것입니다. 다음 두 비트 0936은 객체를 생성하는 프로세스 식별자입니다.
증가
처음 9 바이트는 1 초 이내에 다른 기계와 프로세스에 의해 생성 된 객체가 충돌하지 않도록합니다. 다음 3 바이트 A8B817은 자동으로 증가하여 동일한 두 번째 내에 생성 된 객체가 충돌을 찾지 않도록하여 16777216 레코드의 독창성과 동일한 256에서 3 차 전력을 허용합니다.
객관적인 독창성
클라이언트 나 서버에서 어느 정도 고유 한 것이 보장 될 수 있다고 생각할 수 있습니다.
오해 1. 문서 주문이 삽입 순서와 일치합니까?
단일 스레드 상황
ObjectId의 타임 스탬프, 기계, PID 및 Inc는 동일한 기계와 동일한 프로세스에서 고유 한 것으로 보장 될 수 있습니다.
여기에는 문제가 있습니다. MongoDB 작업은 다중 스레드입니다. A, B, C ... 여러 스레드가 매장 내 작업을 수행 할 때 다른 스레드가 다른 스레드보다 먼저 보장되지 않으므로 순서가 좋지 않습니다.
멀티 스레드, 다기신 또는 다중 프로세스 상황
독특한 것으로 보장 할 수없는 ObjectId의 Mache와 Pid를 살펴 보겠습니다. 그러면 데이터가 훨씬 더 순서가 떨어질 것입니다.
해결책:
컬렉션의 데이터가 변하지 않기 때문에 (CAPPED 컬렉션 포함) 가장 쉬운 방법은 ObjectID를 정렬하는 것입니다.
정렬하는 두 가지 방법이 있습니다.
1. MongoDB 쿼리 문
jQuery query = new query (); if (id! = null) {jquery.addcriteria (Criteria.where ( "_ id"). gt (id)); } jQuery.with (new Sort (sort.direction.asc, "_id"));2.java.util.priorityqueue
비교기 <dbobject> 비교기 = 새 비교기 <dbobject> () {@override public int compart (dbobject o1, dbobject o2) {return (객체) o1.get ( "_ id")). 비교 (객체) o2.get ( "_ id"); }}; PriorityQueue <dbobject> queue = new PriorityQueue <dbobject> (200, 비교기);오해 2 : 여러 클라이언트가 동시성이 높은 경우 주문을 보장 할 수 있습니까?
항상 쓰기가 판독 값 (1 초 이상)보다 훨씬 크지 않도록하는 경우 순서대로 발생하지 않습니다.
다음 예를 살펴 보겠습니다
이제 그림을보고 데이터를 두 번 꺼냅니다
첫 번째
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의 타임 스탬프가 몇 초로 차단되기 때문에 카운터 연산자의 첫 4 자리는 기계 및 프로세스 번호입니다.
1. 특정 시간 간격 (1 초 이상) 이전의 프로세스를 프로세스하여 기계와 프로세스 번호가 장애를 일으키더라도 간격 전에 장애가 없을 것입니다.
2. 단일 포인트 삽입, 원래 여러 지점으로 분산 된 삽입 작업은 이제 기계와 프로세스 번호가 동일하고 카운터 연산자가 레코드를 순서대로 만드는 데 사용됩니다.
여기서 첫 번째 방법을 사용했습니다.
오해 3. mongodb를 사용하여 dbobject_id를 설정하지 않으십니까?
MongoDB 삽입 작업 중에 새로운 DBBASICOBJECT ()가 _ID가 수동으로 설정되지 않는 한 _id가 채워지지 않는다는 것을 모든 사람을 본다. 그렇다면 서버에 설정되어 있습니까?
삽입 작업을위한 코드를 살펴 보겠습니다.
구현 클래스
공개 Writeresult Insert (목록 <dbobject> 목록, com.mongodb.writeConcern 걱정, dbencoder encoder) {if (confer == null) {throw new 불법 불법 행위 ( "쓰기 관심사가 null이 될 수 없다"); } return insert (목록, true, concent, encoder); }추가해야한다는 것을 알 수 있습니다. 기본값은 추가하는 것입니다.
보호 된 Writeresult Insert (목록 <dbobject> 목록, boolean workly, com.mongodb.writeconcern 걱정, dbencoder encoder) {if (encoder == null) encoder = defaultdbencoder.create.create (); if (willtrace ()) {for (dbobject o : list) {trace ( "save :" + _fullnamespace + "" + json.serialize (o)); }} if (whistApply) {for (dbobject o : list) {apply (o); _checkobject (o, false, false); Object ID = O.get ( "_ id"); if (id instanceof objectId) {((ObjectID) id) .notNew (); }}} writeresult last = null; int cur = 0; int maxsize = _mongo.getMaxBsonObjectSize (); while (cur <list.size ()) {outmessage om = outmessage.insert (this, encoder, concent); for (; cur <list.size (); cur ++) {dbobject o = list.get (cur); om.putoBject (o); // 배치 인서트 제한은 서버의 4 x maxBson입니다. 2 x를 사용하여 안전하십시오. 부서지다; }} last = _connector.say (_db, om, 관심); } 마지막으로 반환; }AbjectID 작업을 자동으로 추가하십시오
/** * 호출 {@link dbcollection#apply (com.mongodb.dbobject, boolean)} with with with with with with with with with with with with with with with with <dbobject </code> fields * @return 수정 된 매개 변수 객체 */public object apply (dbobject o) {return apply (o, true); }/** * 호출 {@link dbcollection#doApply (com.mongodb.dbobject)}} 선택적으로 자동 _id 필드 * @param jo 객체를 추가하여 * @param에 필드를 추가하기 위해 <code> @return </code> field> O </code>/code apply (dbobjean jo) id = jo.get ( "_id"); if (restid && id == null) {id = objectId.get (); jo.put ( "_id", id); } doApply (jo); 반환 ID; }보시다시피, ObjectID는 MongoDB 드라이버 패키지에 자동으로 추가됩니다.
저축 방법
공개 Writeresult Save (dbobject jo, writeconcern 걱정) {if (checkreadonly (true)) return null; _checkobject (jo, false, false); Object Id = jo.get ( "_id"); if (id == null || (id instanceof objectId && ((ObjectID) id) .isnew ())) {if (id! = null && id incasticof objectId) ((ObjectID) id) .notNew (); if (confer == null) return insert (jo); 그렇지 않으면 삽입 (Jo, 관심사); } dbobject q = new BasicdBobject (); Q.put ( "_id", id); if (confer == null) RETURN UPDATE (Q, Jo, True, False); 그렇지 않으면 업데이트를 반환합니다 (Q, Jo, True, False, Concern); }요약하면, 기본적으로 ObjectID는 설정없이 서버가 아니라 클라이언트에 의해 생성됩니다.
오해 4. 찾을 수있는 모임이 실제로 자동 증가 변수를 얻을 수 있습니까?
dbobject update = new Basicdbobject ( "$ inc", new Basicdbobject ( "Counter", 1)); dbobject query = new Basicdbobject ( "_ id", key); dbobject result = getMongotemplate (). getCollection (CollectionName) .findandModify (Query, Update); if (result == null) {dbobject doc = new BasicdBobject (); Doc.put ( "Counter", 1L); Doc.put ( "_ id", 키); // 삽입 (collectionName, doc); getMongotemplate (). 저장 (doc, collectionName); 반환 1l; } return (long) result.get ( "counter");자동화 변수를 얻는 것은이 방법을 사용하여 작성되지만 실행 후 알게됩니다.
FindandModify 작동, 먼저 찾기를 실행 한 다음 수정을 실행하므로 결과가 NULL이면 추가되어 반환해야합니다.
위의 내용은 MongoDB의 ObjectId로 인한 오해와 일련의 문제입니다. 나는 그것이 당신에게 도움이되기를 바랍니다. 궁금한 점이 있으면 메시지를 남겨 주시면 편집자가 제 시간에 답장을 드리겠습니다. Wulin.com 웹 사이트를 지원해 주셔서 대단히 감사합니다!