2014-03-26 2 views
1

이 POST 메서드를 호출 할 때 여전히 중복 항목이 있습니다. 이전에 스택 오버플로에 대한 조언을 요청했으며 solution을 받았습니다. 즉, 일관성있는 쿼리를 유지하기 위해 parent/child 방법론을 활용했습니다.높은 복제 데이터 저장소의 중복 항목

모든 데이터를 해당 형식으로 마이그레이션하여 다른 3 개월 동안 실행하도록했습니다. 그러나 문제는 해결되지 않았습니다.

문제가 바로 여기에 해당됩니다. if recordsdb.count() == 1: 항목을 업데이트하려면 true 여야하지만 대신 HRD가 항상 최신 항목을 찾지 않고 대신 새 항목을 만들 수 있습니다.

new_record = FeelTrackerRecord(parent=user.key,...) 

을 그럼에도 불구하고 여전히 검색시, 인적 자원 개발은 여전히 ​​항상 최신 항목을 가져 오지 않습니다 당신이 볼 수 있듯이 권장

것은, 우리는 부모/자식 방법을 통해 녹화에서 읽기/쓰기됩니다

recordsdb = FeelTrackerRecord.query(ancestor = user.key).filter(FeelTrackerRecord.record_date == ...) 

그래서 우리는 이것에 상당히 집착하고 그것을 해결하는 방법을 모른다.

@requires_auth 
    def post(self, ios_sync_timestamp): 
     user = User.query(User.email == request.authorization.username).fetch(1)[0] 
     if user: 
      json_records = request.json['records'] 
      for json_record in json_records: 
       recordsdb = FeelTrackerRecord.query(ancestor = user.key).filter(FeelTrackerRecord.record_date == date_parser.parse(json_record['record_date'])) 
       if recordsdb.count() == 1: 
        rec = recordsdb.fetch(1)[0] 
        if 'timestamp' in json_record: 
         if rec.timestamp < json_record['timestamp']: 
          rec.rating = json_record['rating'] 
          rec.notes = json_record['notes'] 
          rec.timestamp = json_record['timestamp'] 
          rec.is_deleted = json_record['is_deleted'] 
          rec.put() 
       elif recordsdb.count() == 0: 
        new_record = FeelTrackerRecord(parent=user.key, 
             user=user.key, 
             record_date = date_parser.parse(json_record['record_date']), 
             rating = json_record['rating'], 
             notes = json_record['notes'], 
             timestamp = json_record['timestamp']) 
        new_record.put() 
       else: 
        raise Exception('Got more than two records for the same record date - among REST post') 
      user.last_sync_timestamp = create_timestamp(datetime.datetime.today()) 
      user.put() 
      return '', 201 
     else: 
      return '', 401 

가능한 해결 방법 :

난 도망 부모/자식 전략에서 스테핑과 키의 일부로 user.key PLUS date-string를 사용하여이 될 것입니다 해결해야하는 가장 마지막 아이디어.

저장 :

new_record = FeelTrackerRecord(id=str(user.key) + json_record['record_date'], ...) 
new_record.put() 

로드 : 기록 없음없는 경우

key = ndb.Key(FeelTrackerRecord, str(user.key) + json_record['record_date']) 
record = key.get(); 

가 지금은 그렇지 않으면 나는 그것을 업데이트한다 나는 새 항목을 만들한다 확인할 수 있습니다. HRD는 더 이상 기록을 찾지 못할 이유가 없습니다. 이것이 해결책이라고 생각하십니까?

답변

2

가능한 해결 방법은 원래 코드와 동일한 문제가있는 것으로 보입니다. 두 서버가 동일한 명령을 실질적으로 동시에 실행하면 경쟁 조건을 상상해보십시오. 구글의 과잉 프로비저닝으로, 그것은 한동안 일어날 것입니다.

더 강력한 솔루션은 동시성이 일관성 위반을 일으키는 경우 Transactions과 롤백을 사용해야합니다. 사용자 엔티티는 자체 엔티티 그룹의 부모 여야합니다. 트랜잭션 내 사용자 엔터티의 레코드 카운터 필드를 증가시킵니다. 트랜잭션이 성공적으로 완료된 경우에만 새로운 FeelTrackerRecord를 작성하십시오. 따라서 FeelTrackerRecord 엔티티는 User를 부모로 가져야합니다.

편집 : 다음 줄이 사용자 전에 갈 것 코드의 경우 = User.query (... :

Transaction txn = datastore.beginTransaction(); 
try { 

다음과 같은 라인이 사용자 후 갈 것입니다.() :

txn.commit(); 
} finally { 
    if (txn.isActive()) { 
     txn.rollback(); 
    } 
} 

일부 흐름 제어 중첩 세부 사항을 간과 할 수 있습니다.이 개념이 설명하려고하는 개념입니다.

활성 트랜잭션의 경우 여러 프로세스 (예 : 과다 프로비저닝으로 인해 동일한 POST를 동시에 실행하는 여러 서버)에서 두 번째 프로세스가 문서화 된 ConcurrentModificationException을 던지는 동안 첫 번째 프로세스는 put 및 commit와 함께 성공합니다.

편집 2 : 카운터를 증가시키고 예외를 throw 할 수있는 트랜잭션은 새 레코드를 만들어야합니다. 그런 식으로 예외가 발생하면 새 레코드가 만들어지지 않습니다.

+1

감사합니다. 나는 당신이 제공 한 링크를 연구했습니다. 샘플 코드없이 제안 사항을 이해하는 데 정말로 어려움이 있습니다. 제공 한 링크에서 예외가 발생 했으므로 트랜잭션이 해당 사례를 처리 할 수 ​​있습니다. 제 경우에는 예외가 아닙니다. 나는 그 레코드가 존재해야하지만, 그것이 발견되지는 않지만, 사용자의 모든 레코드를 얻고 날짜별로 필터링한다. 따라서이 날짜로 새 레코드가 만들어집니다. 예외는 없습니다. 어떻게 거래가 그것을 해결할 수 있습니까? – Houman

+0

고마워 마틴, 내가 틀렸다면 정정 해줘.하지만 이건 동시에 저장하려고하는 여러 프로세스에 관한 것 같지 않아. 문제는이 줄에서 드문 경우에 레코드를 찾을 수 없다는 것입니다.'recordsdb = FeelTrackerRecord.query (ancestor = user.key) .filter (FeelTrackerRecord.record_date == date_parser.parse (json_record [ 'record_date']))'그러므로 'else if' 문으로 점프하고 새로운 레코드를 생성합니다. Double Entry가 생성되는 순간입니다. 레코드를 업데이트하는 대신 새 레코드를 만듭니다. 우리가 처음에 그 기록을 찾지 못한 이유를 찾아야하지 않습니까? – Houman

+0

나는 무엇을 의미하는지보고 편집 2로 제안을 추가했습니다. –

관련 문제