跳转到主要内容

SQLAlchemy集成到Zope 3

项目描述

SQLAlchemy 和 Zope 3

“z3c.zalchemy”将对象关系映射器 SQLAlchemy 集成到 Zope 3 中,类似于 SQLOS 集成 sqlobject。

zalchemy 尽量不干扰标准 SQLAlchemy 的使用。zalchemy 的主要部分是将 SQLAlchemy 事务集成到 Zope 事务中。这是通过使用一个数据管理器来实现的,该管理器在每个新创建的线程中都会加入 Zope 事务。

zalchemy 使用 zope 中的两阶段提交系统。

这是 zope 中如何使用两阶段提交的。

  1. tpc_begin(txn)

  2. commit(txn)

  3. tpc_vote(txn)

  4. tpc_finish(txn)

  • commit 执行 session.flush(),这实际上执行了所有 SQL 语句。

  • tpc_finish() 在 sqlalchemy 事务中执行 transaction.commit()

  • tpc_abort() 在 sqlalchemy 事务中执行 transaction.rollback()

如果提交失败或另一个 DataManager 失败,则数据不会提交到数据库。

重要

Zope 使用事务模块来处理事务。zalchemy 插入这个机制,并使用自己的数据管理器来使用 Zope 的事务模块。

zalchemy 提供了 z3c.zalchemy.getSession 方法来获取 SQLAlchemy 会话对象。此方法确保会话连接到 Zope 的事务。

永远不要直接从 SQLAlchemy 获取会话!

也很重要,永远不要存储会话的实例。始终直接使用 z3c.zalchemy.getSession。这是因为您永远不知道何时提交事务。提交事务将始终使当前会话无效。对 getSession 的新调用确保创建新的会话。

zalchemy 类实现

使用 SQLAlchemy 与 Zope 一起没有区别。

zalchemy 提供了一种透明的方式将表连接到数据库(引擎)。

一个 SQLAlchemy 引擎表示为一个工具

>>> from z3c.zalchemy.datamanager import AlchemyEngineUtility
>>> engineUtility = AlchemyEngineUtility(
...       'database',
...       'sqlite:///%s'%dbFilename,
...       echo=False,
...       )

我们创建我们的表作为普通的 SQLAlchemy 表。这里重要的是,必须使用 zalchemy 的元数据。请注意,您需要调用 z3c.zalchemy.metadata。

>>> import sqlalchemy
>>> import z3c.zalchemy
>>> table3 = sqlalchemy.Table(
...     'table3',
...     z3c.zalchemy.metadata(),
...     sqlalchemy.Column('id', sqlalchemy.Integer,
...         sqlalchemy.Sequence('atable_id'), primary_key=True),
...     sqlalchemy.Column('value', sqlalchemy.Integer),
...     )

定义一个简单的类,稍后将用于映射到数据库表。

>>> class A(object):
...     pass

现在我们将表映射到我们的类。

>>> sqlalchemy.mapper(A, table3) is not None
True

为了让 zalchemy 做其工作,我们需要注册我们的数据库工具。

>>> from z3c.zalchemy.interfaces import IAlchemyEngineUtility
>>> from zope.component import provideUtility
>>> provideUtility(engineUtility, IAlchemyEngineUtility)

表可以在没有打开事务或会话的情况下创建。如果没有创建会话,则表创建将延迟到 zalchemy.getSession 的下一次调用。

>>> z3c.zalchemy.createTable('table3', '')

zalchemy 自动协调 Zope 的事务管理器与 SQLAlchemy 的会话。所有映射的类都自动与线程局部会话相关联,而该会话反过来又自动连接到一个特殊的数据管理器,该管理器与 Zope 的事务协调。

>>> a = A()
>>> a.value = 1

提交事务将自动触发刷新并清除会话。

>>> import transaction
>>> transaction.commit()

现在让我们尝试在新事务中获取对象(我们已经在新事务中了,因为旧事务已提交)

>>> from z3c.zalchemy.datamanager import getSession as session
>>> a = session().get(A, 1)
>>> a.value
1
>>> transaction.commit()

多个数据库

上述示例假设只有一个数据库。数据库引擎被注册为一个未命名的工具。未命名的工具始终是新的会话的默认数据库。

这自动将每个表分配给默认引擎。

对于多个数据库,可以将表分配给引擎。

我们创建一个新的数据库引擎

>>> engine2Util = AlchemyEngineUtility(
...     'engine2',
...     'sqlite:///%s'%dbFilename2,
...     echo=False,
...     )

因为我们已经有一个默认引擎,所以我们必须为新引擎提供一个名称。

>>> provideUtility(engine2Util, IAlchemyEngineUtility, name='engine2')
>>> bTable = sqlalchemy.Table(
...     'bTable',
...     z3c.zalchemy.metadata(),
...     sqlalchemy.Column('id', sqlalchemy.Integer,
...         sqlalchemy.Sequence('btable_id'), primary_key=True),
...     sqlalchemy.Column('value', sqlalchemy.String),
...     )
>>> class B(object):
...     pass
>>> B.mapper = sqlalchemy.mapper(B, bTable)

将 bTable 分配给新引擎并创建表。这次我们在会话内部执行。

>>> z3c.zalchemy.assignTable('bTable', 'engine2')
>>> z3c.zalchemy.createTable('bTable', 'engine2')
>>> b = B()
>>> b.value = 'b1'
>>> a = A()
>>> a.value = 321
>>> transaction.commit()
>>> a = session().get(A, 1)
>>> b = session().get(B, 1)
>>> str(b.value)
'b1'
>>> transaction.commit()

也可以将类分配给数据库

>>> class Aa(object):
...     pass
>>> sqlalchemy.mapper(Aa, table3) is not None
True

现在我们可以将类分配给引擎

>>> z3c.zalchemy.assignClass(Aa, 'engine2')

问题是现在我们在‘engine2’中没有表。我们可以使用 createTable 的额外参数来创建表

>>> z3c.zalchemy.createTable('table3', 'engine2')
>>> aa = Aa()
>>> aa.value = 100
>>> transaction.commit()

不同数据库中具有相同名称的表

如果我们有两个包含具有不同结构但名称相同的表的两个数据库,我们需要显式地将表分配给数据库。这必须通过请求特定引擎的元数据来完成。

>>> b2Table = sqlalchemy.Table(
...     'bTable',
...     z3c.zalchemy.metadata('b2Engine'),
...     sqlalchemy.Column('id', sqlalchemy.Integer,
...         sqlalchemy.Sequence('btable_id'), primary_key=True),
...     sqlalchemy.Column('b2value', sqlalchemy.String),
...     )

现在我们可以通过提供引擎来请求表。

>>> z3c.zalchemy.metadata.getTable('b2Engine', 'bTable', True)
Table('bTable',...

如果我们已为“默认”引擎指定了表,则可以请求“b2Engine”的“bTable”,并回退到默认引擎。

>>> z3c.zalchemy.metadata.getTable('b2Engine', 'table3', True)
Table('table3',...

更改

0.2.2 (2011-08-05)

  • 修复打包问题:声明命名空间包“z3c”。

0.2.1 - 2007-11-13

  • 使用 savepoints 的冲突检测不起作用。

0.2 - 2007-09-27

  • 添加了注册特定于数据库的适配器以进行冲突检测和发布者可能重新执行的方法。

  • 使用 sqlalchemy 的 threadlocal 策略而不是自己执行。

  • 添加了对乐观 savepoints 的支持。这可以像 ZODB 发生的那样使用,在不提交的情况下刷新中间工作。

  • 提供与 Zope 事务机制更紧密的集成。会话现在自动与新对象相关联。我们依赖于 sqlalchemy 的 SessionContext 对象,该对象为每个线程提供会话。现在很少需要调用 session.save(object)

    引入了一个不兼容的更改:在注册一个(未命名的)引擎工具之前,您不能调用 getSession。这样做将引发 ValueError。

0.1.1 - 2007-06-27

  • 修复了 TRANSACTION.txt 中的失败测试,其中异常演示返回了一个字符串,但实际上是一个 Unicode 字符串。

0.1 - 永远未发布

  • 这应该是第一个发布版本,但我们错过了一个损坏的测试。请参阅 0.1.1。

项目详情


下载文件

下载适用于您平台的文件。如果您不确定选择哪个,请了解更多关于 安装包 的信息。

源分发

z3c.zalchemy-0.2.2.tar.gz (29.6 kB 查看哈希值)

上传时间

由 ... 支持

AWS AWS 云计算和安全赞助商 Datadog Datadog 监控 Fastly Fastly CDN Google Google 下载分析 Microsoft Microsoft PSF赞助商 Pingdom Pingdom 监控 Sentry Sentry 错误日志 StatusPage StatusPage 状态页面