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 transaction
0

现在我们为斯蒂芬添加一个地址。地址也是持久对象:

< Buff行情>
>>> import transaction
1

mongopersist支持一个名为 \u p\u mongo\u collection的特殊属性, 它允许您指定要使用的自定义集合。

< Buff行情>
>>> import transaction
2

请注意,地址不会立即保存在数据库中:

< Buff行情>
>>> import transaction
3

但一旦我们提交了事务,一切都可用:

< Buff行情>
>>> import transaction
4
>>> import transaction
5
>>> import transaction
6

非持久对象

如您所见,即使引用看起来也很好,并且使用了标准的mongo db 参考构造。但如果任意的,非持久的,可挑剔的, 物体?好吧,让我们为此创建一个phone number对象:

< Buff行情>
>>> import transaction
7
>>> import transaction
8

现在我们提交事务并再次查看mongo文档:

< Buff行情>
>>> import transaction
9
>>> import datetime
>>> import persistent
0

如您所见,对于任意的非持久性对象,我们需要在 子文档,但非常少。如果返回 一个更复杂的结构,写更多的元数据。下一步我们会看到的 存储日期和其他任意数据时:

< Buff行情>
>>> import datetime
>>> import persistent
1
>>> import datetime
>>> import persistent
2

如您所见,字典键总是转换为Unicode,元组是 由于bson没有两种序列类型,因此始终保持为列表。

< Buff行情>
>>> import datetime
>>> import persistent
3

自定义序列化程序

如你所见,生日的系列化几乎是理想的。我们可以, 但是,请提供使用序号存储数据的自定义序列化程序。

< Buff行情>
>>> import datetime
>>> import persistent
4
>>> import datetime
>>> import persistent
5

让我们再来看看:

< Buff行情>
>>> import datetime
>>> import persistent
6
>>> import datetime
>>> import persistent
7

好多了!

作为子文档的持久对象

以便更好地控制哪些对象接收自己的集合 如果没有,开发人员可以提供一个特殊的标志来标记 持久类,使其成为其父对象文档的一部分:

< Buff行情>
>>> import datetime
>>> import persistent
8

\u p_u mongo_u sub_u对象用于将一类对象标记为只是部分对象 另一份文件:

< Buff行情>
>>> import datetime
>>> import persistent
9
>>> 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

欢迎加入QQ群-->: 979659372 Python中文网_新手群

推荐PyPI第三方库


热门话题
java AnimatedVectorDrawable支持库和“pathData”动画   java Qt Jambi:QistTractListModel未显示在QListView中   单击按钮时清除共享首选项   java线程池大小应该远大于内核数+1   linux编译错误java hadoop程序   java不包括findBugs发现的bug   SpringJava。lang.NoClassDefFoundError:org。阿帕奇。贾斯珀。埃尔。ELContextImpl(初始化失败)   使用AVL树的java字典数组   java如何使用数组数据执行jsoup请求?Jsoup使用数组数据发布请求并从php服务器获取json   java jdbc在sql server 2008 r2上存储的png图像提供了不完整的数据   java坏路径警告,它来自哪里?   java从HashMap<String,ArrayList<String>>   java HttpSolrserver已被弃用,无法让HttpSolrClient毫无例外地工作   java如何使用坐标很少的仿射变换?   java在JaxRs中存储会话对象