Python专题之RDBMS和ORM

Python专题之RDBMS和ORM

基础

RDBMS = Relational DataBase Management System, 关系型数据库管理系统。
ORM = Object-Relational Mapping, 对象关系映射。

RDBMS是关于将数据以普通表单的形式存储的,而SQL是关于如何处理关系代数的。
二者结合就可以对数据进行存储,同时回答关于数据的问题。然而,在面向对象程序中使用ORM有许多常见的困难,统称为对象关系阻抗失配(object-relational impedance mismatch, http://en.wikipedia.org/wiki/Object-relational_impedance_mismatch)。
根本在于,关系型数据库和面向对象程序对数据有不同的表示方式,彼此之间不能很好地映射:不管怎么做,将SQL表映射到Python的类都无法得到最优的结果。

ORM应该使数据的访问更加容易,这些工具会抽象创建查询、生成SQL的过程,无需自己处理。但是,你迟早会发现有些想做的数据库操作是这个抽象层不允许的。为了更有效地利用数据库,必须对SQL和RDBMS有深入了解以便能直接写自己的查询而无需每件事都依赖抽象层。

但这不是说要完全避免用ORM。ORM库可以帮助快速建立应用模型的原型,有些甚至能提供非常有用的工具,如模式(schema)的升降级。重要的是了解它并不能完全替代RDBMS。许多开发人员试图在它们选择的语言中解决问题而不使用它们的模型API,通常他们给出的方案去并不优雅。

设想一个用来记录消息的SQL表。它有一个名为id的列作为主键和一个用来存放消息的字符串列。

CREATE TABLE message (
    id serial PRIMARY KEY,
    content text
);

我们希望收到消息时避免重复记录,所以一个典型的开发人员会这么写:

if message_table.select_by_id(message.id):
    raise DuplicateMessage(message)
else:
    message_table.insert(message)

这在大多数情况下肯定可行,但它有些主要的弊端。

  • 它实现了一个已经在SQL模式中定义了的约束,所以有点儿代码重复。
  • 执行了两次SQL查询,SQL查询的执行可能会时间很长而且需要与SQL服务器往返的通信,造成额外的延迟。
  • 没有考虑到在调用select_by_id之后程序代码insert之前,可能有其他人插入一个重复消息的可能性,这会引发程序抛出异常。

下面是一种更好的方式,但需要RDBMS服务器合作而不是将其看作是单纯的存储。

try:
    message_table.insert(message)
except UniqueViolationError:
    raise DuplicateMessage(message)

这段代码以更有效的方式获得了同样的效果而且没有任何竞态条件(race condition)问题。这是一种非常简单的模式,而且和ORM完全没有冲突。这个问题在于开发人员将SQL数据库看作是单纯的存储并且在他们的控制器代码而不是他们的模型中重复他们已经(或者可能)在SQL中实现的约束。

将SQL后端看作是模型API是有效利用它的好办法。通过它本身的过程性语言编写简单的函数调用即可操作存储在RDBMS中的数据。

另外需要强调的一点是,ORM支持多种数据库后端。许多ORM库都将其看作一项功能来吹嘘,但它实际上去是个陷阱,等待诱捕那些毫无防备的开发人员。没有任何ORM库能提供对所有RDBMS功能的抽象,所以你将不得不消减你的代码,只支持那些RDBMS最基本的功能,而且将不能在不破坏抽象层的情况下使用任何RDBMS的高级功能。

有些在SQL中尚未标准化的简单得事情在使用ORM时处理起来会很痛苦,如处理时间戳操作。如果代码写成了与RDBMS无关的就更是如此。基于这一点,在选择适合你的应用程序的RDBMS时要更加仔细。

最好自己实现一个中间层,通过中间层来使用ORM。在发现更合适的ORM时,替换掉。

Python中最常使用的(和有争议的事实标准)ORM库是SQLAlchemy。它支持大量的不同后端并且对大多数通用操作都提供了抽象。模式升级可以通过第三方库完成,如alembic

有些框架,如Django,提供了它们自己的ORM库。如果选择使用一个框架,那么使用内置的库是明智的选择,通常与外部ORM库相比,内置的库与框架集成得更好。

用Flask和PostgreSQL流化数据

建议

RDBMS提供的主要服务如下:

什么时候可以放心使用ORM:

  1. 快速发布产品。 但当你取得一定成功时,应该迅速把ORM从你的代码库中移除。
  2. CRUD应用。真正要处理的只是一次编辑一个元组,并且不关心性能问题。例如,基本的管理应用界面。

发表评论

电子邮件地址不会被公开。 必填项已用*标注