Mongo持久性后端
mongopersist的Python项目详细描述
Mongo数据持久性
本文档概述了Mongopersist的一般功能 包裹。 mongopersist 是一个用于持久化的mongo存储实现 python对象。它不是zodb的存储器。
mongopersist的目标是提供一个序列化的数据管理器。 对象到事务边界处的Mongo。Mongo数据管理器是 持久数据管理器,它处理事务边界上的事件(请参见 transaction.interfaces.idatamanager )以及 持久性框架(请参见persistent.interfaces.ipersistentdatamanager)。
数据管理器的实例应该与 事务,这意味着假设您创建了一个新的数据管理器 创建新事务时:
< Buff行情>>>> import transaction
注意: conn 对象是一个 pymongo.connection.connection 实例。在 这种情况下,我们的测试使用 Mongopersist_测试 数据库。
现在我们定义一个简单的持久对象:
< Buff行情>>>> import datetime >>> import persistent
>>> class Person(persistent.Persistent): ... ... def __init__(self, name, phone=None, address=None, friends=None, ... visited=(), birthday=None): ... self.name = name ... self.address = address ... self.friends = friends or {} ... self.visited = visited ... self.phone = phone ... self.birthday = birthday ... self.today = datetime.datetime.now() ... ... def __str__(self): ... return self.name ... ... def __repr__(self): ... return '<%s %s>' %(self.__class__.__name__, self)
稍后我们将填写其他对象。但现在,让我们创建一个新的 将其储存在Mongo中:
< Buff行情>>>> stephan = Person(u'Stephan') >>> stephan <Person Stephan>
datamanager提供了一个 root 属性,其中对象树是根 可以储存。它的特殊之处在于它可以立即写入数据 到数据库:
< Buff行情>>>> dm.root['stephan'] = stephan >>> dm.root['stephan'] <Person Stephan>
自定义持久性集合
默认情况下,持久对象存储在具有python的集合中 课程路径:
< Buff行情>>>> from mongopersist import serialize >>> person_cn = serialize.get_dotted_name(Person) >>> person_cn '__main__.Person'
>>> import pprint >>> pprint.pprint(list(conn[DBNAME][person_cn].find())) [{u'_id': ObjectId('4e7ddf12e138237403000000'), u'address': None, u'birthday': None, u'friends': {}, u'name': u'Stephan', u'phone': None, u'today': datetime.datetime(2011, 10, 1, 9, 45), u'visited': []}]
如您所见,为此人存储的文档看起来非常mongo。但是哦 不,我忘记给斯蒂芬指定全名了。让我们这样做:
< Buff行情>>>> dm.root['stephan'].name = u'Stephan Richter'
这一次,数据不会自动保存:
< Buff行情>>>> conn[DBNAME][person_cn].find_one()['name'] u'Stephan'
所以我们必须先提交事务:
< Buff行情>>>> import transaction0
现在我们为斯蒂芬添加一个地址。地址也是持久对象:
< Buff行情>>>> import transaction1
mongopersist支持一个名为 \u p\u mongo\u collection的特殊属性, 它允许您指定要使用的自定义集合。
< Buff行情>>>> import transaction2
请注意,地址不会立即保存在数据库中:
< Buff行情>>>> import transaction3
但一旦我们提交了事务,一切都可用:
< Buff行情>>>> import transaction4
>>> import transaction5
>>> import transaction6
非持久对象
如您所见,即使引用看起来也很好,并且使用了标准的mongo db 参考构造。但如果任意的,非持久的,可挑剔的, 物体?好吧,让我们为此创建一个phone number对象:
< Buff行情>>>> import transaction7
>>> import transaction8
现在我们提交事务并再次查看mongo文档:
< Buff行情>>>> import transaction9
>>> import datetime >>> import persistent0
如您所见,对于任意的非持久性对象,我们需要在 子文档,但非常少。如果返回 一个更复杂的结构,写更多的元数据。下一步我们会看到的 存储日期和其他任意数据时:
< Buff行情>>>> import datetime >>> import persistent1
>>> import datetime >>> import persistent2
如您所见,字典键总是转换为Unicode,元组是 由于bson没有两种序列类型,因此始终保持为列表。
< Buff行情>>>> import datetime >>> import persistent3
自定义序列化程序
如你所见,生日的系列化几乎是理想的。我们可以, 但是,请提供使用序号存储数据的自定义序列化程序。
< Buff行情>>>> import datetime >>> import persistent4
>>> import datetime >>> import persistent5
让我们再来看看:
< Buff行情>>>> import datetime >>> import persistent6
>>> import datetime >>> import persistent7
好多了!
作为子文档的持久对象
以便更好地控制哪些对象接收自己的集合 如果没有,开发人员可以提供一个特殊的标志来标记 持久类,使其成为其父对象文档的一部分:
< Buff行情>>>> import datetime >>> import persistent8
\u p_u mongo_u sub_u对象用于将一类对象标记为只是部分对象 另一份文件:
< Buff行情>>>> import datetime >>> import persistent9
>>> class Person(persistent.Persistent): ... ... def __init__(self, name, phone=None, address=None, friends=None, ... visited=(), birthday=None): ... self.name = name ... self.address = address ... self.friends = friends or {} ... self.visited = visited ... self.phone = phone ... self.birthday = birthday ... self.today = datetime.datetime.now() ... ... def __str__(self): ... return self.name ... ... def __repr__(self): ... return '<%s %s>' %(self.__class__.__name__, self)0
>>> class Person(persistent.Persistent): ... ... def __init__(self, name, phone=None, address=None, friends=None, ... visited=(), birthday=None): ... self.name = name ... self.address = address ... self.friends = friends or {} ... self.visited = visited ... self.phone = phone ... self.birthday = birthday ... self.today = datetime.datetime.now() ... ... def __str__(self): ... return self.name ... ... def __repr__(self): ... return '<%s %s>' %(self.__class__.__name__, self)1
我们希望对象持久化的原因是这样它们可以接受更改 自动:
< Buff行情>>>> class Person(persistent.Persistent): ... ... def __init__(self, name, phone=None, address=None, friends=None, ... visited=(), birthday=None): ... self.name = name ... self.address = address ... self.friends = friends or {} ... self.visited = visited ... self.phone = phone ... self.birthday = birthday ... self.today = datetime.datetime.now() ... ... def __str__(self): ... return self.name ... ... def __repr__(self): ... return '<%s %s>' %(self.__class__.__name__, self)2
收藏共享
由于mongo非常灵活,所以有时存储多个类型是有意义的 属于同一集合中的(类似的)对象。在这种情况下,你会指示 对象类型,将其python路径存储为文档的一部分。
警告:请注意,尽管此方法效率较低,因为 必须加载文档才能创建导致更多数据库的重影 Access,
< Buff行情>>>> class Person(persistent.Persistent): ... ... def __init__(self, name, phone=None, address=None, friends=None, ... visited=(), birthday=None): ... self.name = name ... self.address = address ... self.friends = friends or {} ... self.visited = visited ... self.phone = phone ... self.birthday = birthday ... self.today = datetime.datetime.now() ... ... def __str__(self): ... return self.name ... ... def __repr__(self): ... return '<%s %s>' %(self.__class__.__name__, self)3
为了完成集合共享,只需创建另一个类 与另一个具有相同字符串的 确保)。
现在给斯蒂芬一个扩展地址。
< Buff行情>>>> class Person(persistent.Persistent): ... ... def __init__(self, name, phone=None, address=None, friends=None, ... visited=(), birthday=None): ... self.name = name ... self.address = address ... self.friends = friends or {} ... self.visited = visited ... self.phone = phone ... self.birthday = birthday ... self.today = datetime.datetime.now() ... ... def __str__(self): ... return self.name ... ... def __repr__(self): ... return '<%s %s>' %(self.__class__.__name__, self)4
加载地址时,地址类型应正确:
< Buff行情>>>> class Person(persistent.Persistent): ... ... def __init__(self, name, phone=None, address=None, friends=None, ... visited=(), birthday=None): ... self.name = name ... self.address = address ... self.friends = friends or {} ... self.visited = visited ... self.phone = phone ... self.birthday = birthday ... self.today = datetime.datetime.now() ... ... def __str__(self): ... return self.name ... ... def __repr__(self): ... return '<%s %s>' %(self.__class__.__name__, self)5
棘手的案例
基本可变类型的更改
棘手,棘手。我们如何使框架检测可变的变化 对象,如列表和字典?答:我们会记录下 它们所属的持久对象并提供持久实现。
< Buff行情>>>> class Person(persistent.Persistent): ... ... def __init__(self, name, phone=None, address=None, friends=None, ... visited=(), birthday=None): ... self.name = name ... self.address = address ... self.friends = friends or {} ... self.visited = visited ... self.phone = phone ... self.birthday = birthday ... self.today = datetime.datetime.now() ... ... def __str__(self): ... return self.name ... ... def __repr__(self): ... return '<%s %s>' %(self.__class__.__name__, self)6
>>> class Person(persistent.Persistent): ... ... def __init__(self, name, phone=None, address=None, friends=None, ... visited=(), birthday=None): ... self.name = name ... self.address = address ... self.friends = friends or {} ... self.visited = visited ... self.phone = phone ... self.birthday = birthday ... self.today = datetime.datetime.now() ... ... def __str__(self): ... return self.name ... ... def __repr__(self): ... return '<%s %s>' %(self.__class__.__name__, self)7
列表也是如此:
< Buff行情>>>> class Person(persistent.Persistent): ... ... def __init__(self, name, phone=None, address=None, friends=None, ... visited=(), birthday=None): ... self.name = name ... self.address = address ... self.friends = friends or {} ... self.visited = visited ... self.phone = phone ... self.birthday = birthday ... self.today = datetime.datetime.now() ... ... def __str__(self): ... return self.name ... ... def __repr__(self): ... return '<%s %s>' %(self.__class__.__name__, self)8
>>> class Person(persistent.Persistent): ... ... def __init__(self, name, phone=None, address=None, friends=None, ... visited=(), birthday=None): ... self.name = name ... self.address = address ... self.friends = friends or {} ... self.visited = visited ... self.phone = phone ... self.birthday = birthday ... self.today = datetime.datetime.now() ... ... def __str__(self): ... return self.name ... ... def __repr__(self): ... return '<%s %s>' %(self.__class__.__name__, self)9
循环非持久引用
存储在子文档中的任何可变对象都不能有多个 对象树中的引用,因为没有全局引用。这些 检测并报告循环引用:
< Buff行情>>>> stephan = Person(u'Stephan') >>> stephan <Person Stephan>0
>>> stephan = Person(u'Stephan') >>> stephan <Person Stephan>1
>>> stephan = Person(u'Stephan') >>> stephan <Person Stephan>2
>>> stephan = Person(u'Stephan') >>> stephan <Person Stephan>3
>>> stephan = Person(u'Stephan') >>> stephan <Person Stephan>4
循环持久引用
一般来说,持久对象之间的循环引用不是问题, 因为我们总是只存储到对象的链接。然而,有一种情况是 循环依赖成为一个问题。
如果使用循环引用设置对象树,然后将该树添加到 存储必须在序列化期间立即插入对象,以便 可以创建引用。但是,需要注意的是,只需创建 最小的引用对象,以便系统不尝试递归地 减少状态。
< Buff行情>>>> stephan = Person(u'Stephan') >>> stephan <Person Stephan>5
>>> stephan = Person(u'Stephan') >>> stephan <Person Stephan>6
>>> stephan = Person(u'Stephan') >>> stephan <Person Stephan>7
>>> stephan = Person(u'Stephan') >>> stephan <Person Stephan>8
容器和集合
既然我们已经谈了很多关于存储一个对象的血腥细节, 那么反映整个集合的映射呢,例如 人员集合。
可以采取许多方法。以下实现 将文档中的属性定义为映射键,并将 收藏:
< Buff行情>>>> stephan = Person(u'Stephan') >>> stephan <Person Stephan>9
映射将数据管理器作为参数。一个人可以很容易地创造一个 自动分配数据管理器的子类。让我们看看:
< Buff行情>>>> dm.root['stephan'] = stephan >>> dm.root['stephan'] <Person Stephan>0
没有人在列表中的原因是没有文档具有密钥 或者密钥为空。让我们改变一下:
< Buff行情>>>> dm.root['stephan'] = stephan >>> dm.root['stephan'] <Person Stephan>1
>>> dm.root['stephan'] = stephan >>> dm.root['stephan'] <Person Stephan>2
还要注意,对任何其他人设置"short name"属性将添加 它到映射:
<集团】kQu>>>> dm.root['stephan'] = stephan >>> dm.root['stephan'] <Person Stephan>3
写入冲突检测
由于mongo不支持mvcc,因此它不提供写的概念。 冲突检测。但是,简单的写冲突检测很容易 使用文档上的序列号实现。
让我们重置数据库并创建一个启用了冲突的数据管理器 检测:
< Buff行情>>>> dm.root['stephan'] = stephan >>> dm.root['stephan'] <Person Stephan>4
现在我们添加一个人并查看序列号是否已存储。
< Buff行情>>>> dm.root['stephan'] = stephan >>> dm.root['stephan'] <Person Stephan>5
接下来,我们更改此人并再次提交:
< Buff行情>>>> dm.root['stephan'] = stephan >>> dm.root['stephan'] <Person Stephan>6
现在,我们开始一个新的事务,并进行一些修改:
< Buff行情>>>> dm.root['stephan'] = stephan >>> dm.root['stephan'] <Person Stephan>7
但是,同时另一个事务会修改对象。(我们会做的 为了简单起见,这里直接通过mongo。)
< Buff行情>>>> dm.root['stephan'] = stephan >>> dm.root['stephan'] <Person Stephan>8
现在,我们正在更改的事务尝试提交:
< Buff行情>>>> dm.root['stephan'] = stephan >>> dm.root['stephan'] <Person Stephan>9
>>> from mongopersist import serialize >>> person_cn = serialize.get_dotted_name(Person) >>> person_cn '__main__.Person'0