4.3 ORM编程
除了直接用SQL语句操作关系数据库,Python中的另一种与关系数据库进行交互的技术是ORM。本节介绍ORM的概念和Python中的ORM包。
4.3.1 ORM理论基础
ORM(Object-Relational Mapping,对象关系映射)的作用是在关系数据库和业务实体对象之间做一个映射,这样开发者在操作数据库中的数据时,就不需要再去和复杂的SQL语句打交道,只需简单地操作对象的属性和方法即可。所有的ORM必须具备3方面的基本能力:映射技术、CRUD操作和缓存优化。
1. 映射技术
面向对象是从软件工程的基本原则(如耦合、聚合、封装)的基础上发展而来的,而关系数据库是从数学理论的基础上发展而来的,两套理论存在显著的区别,ORM通过映射机制将两种技术联系起来。每种编程语言都有自己的ORM库,例如,Java的Hibernate、iBATIS,C#的Grove、LINQ,Python的SQLAlchemy等,所有这些ORM库都必须解决如下3个映射问题。
• 数据类型映射:将数据库的类型映射为编程语言自身的类型。数据类型映射解决了由数据表列(Column)类型向编程语言类型转换的问题。例如,SQLAlchemy中定义了一系列的数据类型(SmallInteger、Float、Time等)用于对应数据库中的类型。
• 类映射:将数据表定义映射为编程语言自身的类,这样数据表中的每一条记录就可以映射为一个编程语言自身的对象。因为数据表的定义本身在每个业务场景中各不一样,所以需要开发者通过配置文件或代码文件的方式明确类映射。在SQLAlchemy中开发者通过定义继承自declarative_base()返回的类型来实现类映射。
• 关系映射:将数据库中基于外键的关系连接转换为编程语言中基于对象引用的关系连接。在SQLAlchemy中通过在数据表类中定义relationship()字段,使开发者能够指定数据表之间的连接关系。
2. CRUD操作
CRUD是做数据库处理时的增加(Create)、读取(Retrieve,重新得到数据)、更新(Update)和删除(Delete)几个单词的首字母组合。在SQL中通过INSERT、SELECT、UPDATE、DELETE四种语句实现CRUD。而由于ORM对开发者屏蔽了SQL,因此所有的ORM库必须提供自己的一套CRUD方案。
大多数库会为数据对象提供insert、update、delete、query等函数实现CRUD,并提供beginTransaction、commit、rollback等函数管理事务。当开发者调用这些函数时,ORM自动执行下列操作。
• 将这些调用转换为SQL语句。
• 通过数据库引擎发送给数据库执行。
• 将数据库返回的结果记录用ORM映射技术转换为类对象。
3. 缓存优化
由于数据库操作通常比较耗时,因此大多数ORM提供数据缓存优化的功能,最基本的缓存优化功能如下。
• 将从数据库中查询到的数据以类对象的形式保存在内存中,以便之后再用时随时提取。
• 在真正需要读取查询结果时才执行数据库的SELECT操作,而不是在ORM查询命令执行时查询数据库。
4. 为什么使用ORM
在学习了ORM的基本原理后,我们总结ORM的优点如下。
• 向开发者屏蔽了数据库的细节,使开发者无须与SQL语句打交道,提高了开发效率。
• 便于数据库迁移。由于每种数据库的SQL语法有细微差别,因此基于SQL的数据访问层在更换数据库时通常需要花费大量的时间调试SQL语句。而ORM提供了独立于SQL的接口,ORM引擎会处理不同数据库之间的差异,所以迁移数据库时无须更改代码。
• 应用缓存优化等技术有时可以提高数据库操作的效率。
4.3.2 Python ORM库介绍
ORM在开发者和数据库之间建立了一个中间层,把数据库中的数据转换成了Python中的对象实体,这样既屏蔽了不同数据库之间的差异性,又使开发者可以非常方便地操作数据库中的数据,而且可以使用面向对象的高级特性。
Python中提供ORM支持的组件有很多,每个组件的应用领域稍有区别,但是数据库操作的理论原理是相同的。对比较著名的Python数据库的ORM框架介绍如下。
• SQLAlchemy:Python中最成熟的ORM框架,资源和文档都很丰富。大多数Python Web框架对其都有很好的支持,能够胜任大多数应用场合。SQLAlchemy被认为是Python事实上的ORM标准。
• Django ORM:Python世界中大名鼎鼎的Django Web框架独用的ORM技术。Django是一个大而全的框架,这使得其灵活性大大降低。其他Python Web框架可以随意更换ORM,但在Django中不能这样做,因为Django内置的很多model是用Django内置ORM实现的。
• Peewee:小巧灵活,是一个轻量级ORM。Peewee是基于SQLAlchemy内核开发的,整个框架由一个文件构成。Peewee提供了对多种数据库的访问方式,如SQLite、MySQL、PostgreSQL,适用于功能简单的小型网站。
• Storm:一个中型的ORM库,比SQLAlchemy和Django等轻量,比Peewee的功能更丰富。Storm要求开发者编写数据表的DDL代码,而不能直接从数据表类定义中自动生成表定义。
• SQLObject:与SQLAlchemy相似,也是一套大而全的ORM。SQLObject的特点是它的设计借鉴了Ruby on Rails的ActiveRecord模型,使得熟悉Ruby的开发者非常容易上手。
4.3.3 实战演练:Peewee库编程
本书中篇的Django框架和Flask框架部分将会详细介绍Django ORM和SQLAlchemy的使用方法,此处对轻量级框架Peewee的使用方法进行介绍,以便读者能够迅速掌握ORM的编程思路。
注意:在实践Peewee之前需要先通过pip install peewee命令安装该组件。
由于在一般情况下ORM库自身的缓存优化机制可以满足大多数场景的需要,因此使用ORM的编程通常由两部分组成:定义数据表到Python ORM类的映射关系;连接数据库并进行CRUD等操作。
【示例4-2】以表4.1和表4.2定义的course和teacher数据表为例,用Peewee定义Python ORM类的示例代码如下:
对本示例代码的解析如下。
• 首先引入了Peewee包。
• 用SqliteDatabase()类定义了SQLite的数据库实例。对于其他数据库类型,可以使用相似的MySQLDatabase()及PostgresqlDatabase()等。
• 定义了ORM基类BaseModel,在其中指定了公用的属性database值为之前建立的SQLite连接。
• 类型映射,Peewee中预定义了一系列的数据类型,用于定义数据表中的列,在本例中用到了PrimaryKeyField(主键)、CharField(字符串)、IntegerField(整型)、BooleanField(布尔型)等。
• 表映射:定义了两个对象类Course和Teacher,用于映射数据表course和teacher,注意在每个类的Meta中设置了数据库中该类对应的真实表名。
• 关系映射:在Teacher中通过ForeignKeyField设置了其与Course的连接关系,ForeignKeyField的参数to_field用于指定被连接的字段名,related_name参数为该关系赋予了一个名字。
• 用CLASSNAME.create_table()自动在数据库中建立符合该类定义的数据表。
【示例4-3】下面的代码演示了使用如上ORM映射对数据内容进行增、删、改、查的方法:
在该段代码中分别演示了新建表、增加新记录、查询单行、更新单个记录对象、删除单条对象,以及一些复杂的查询、更新技巧。
现在尝试运行【示例4-2】与【示例4-3】,得到的结果如下:
读者可逐条对比代码与上述结果。