当调用此POST方法时,我们仍然很少有重复条目的情况。
之前,我曾就Stack溢出问题征询过意见,并给了我一个solution,即利用parent/child方法保留了高度一致的查询。

我已将所有数据迁移到该表单中,并允许其再运行3个月。
但是,问题从未解决。

这个条件if recordsdb.count() == 1:就在这里
为了更新条目,它应该为true,但是HRD可能并不总是找到最新的条目,而是创建一个新的条目。

如您所见,我们正在按照推荐的方式通过父/子方法从记录中进行写入/读取:

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


然而,在检索时,HRD仍不总是获取最新条目:

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();


现在我可以检查记录是否为None,我将创建一个新条目,否则将对其进行更新。希望HRD没有理由不再查找该记录。
您认为这是有保证的解决方案吗?

最佳答案

可能的解决方案似乎与原始代码有相同的问题。想象一下,如果两个服务器实际上同时执行相同的指令,就会出现争用情况。由于Google的超额配置,这肯定会偶尔发生。

当并发导致一致性冲突时,更可靠的解决方案应使用Transactions和回滚。用户实体应该是其自己的实体组的父级。在事务内的用户实体中增加记录计数器字段。仅当事务成功完成时,才创建新的FeelTrackerRecord。因此,FeelTrackerRecord实体必须以User作为父级。

编辑:就您的代码而言,以下行将在user = User.query(...之前进行:

Transaction txn = datastore.beginTransaction();
try {


并且以下行将在user.put()之后:

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


这可能会忽略一些流控制嵌套细节,这是该答案试图描述的概念。

对于活动事务,如果多个进程(例如,由于过多配置而在多个服务器上同时执行同一POST),则第一个进程将成功完成其放置和提交操作,而第二个进程将抛出已记录的ConcurrentModificationException。

编辑2:增加计数器(并可能引发异常)的事务也必须创建新记录。这样,如果引发异常,则不会创建新记录。

关于python - 高复制数据存储中的重复条目,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/22665098/

10-08 22:46
查看更多