11.9 总结

    我们从 3 个方面来了解 SQLite 的基本使用:直接访问、通过一个访问层和通过SQLAlchemy这个ORM。我们必须创建SQL DDL语句,可以在应用中直接执行,或将其放在一个访问层中,也可以使用由SQLAlchemy类定义所创建的DDL。至于操作数据,将使用 SQL DML 语句,可以直接在过程式设计中完成,或者使用自己的访问层,或使用SQLAlchemy来创建SQL。

    11.9.1 设计要素和折中方案

    sqlite3 模块的优势之一是允许我们存储不同的项。由于使用了一个支持并发写操作的数据库,因此可以支持多个进程同时修改数据,需要依靠SQLite中内部的锁机制来完成并发的处理。

    使用一个关系数据库会强加很多限制。我们需要考虑如何将对象映射到数据库表中的行。

    • 可以直接使用SQL,只使用SQL中所支持的列类型,并最大限度地不使用面向对象的类。
    • 可以对SQLite进行扩展,手动进行映射,将对象作为SQLite的BLOB列处理。
    • 可以写自己的访问层,用来完成对象和SQL中行的适配和转换。
    • 可使用一个ORM层来完成行与对象之间的映射。

    11.9.2 映射的方法

    混合使用Python和SQL的问题在于,总会想要使用一种“全部唱歌、全部跳舞、全部SQL”的方案。关系数据库是一个很好的平台,Python引入了不必要的面向对象功能会对它造成阻碍。

    全部是SQL,没有对象的设计方法有时对于特定的问题是合理的。尤其是,支持这个观点的人认为使用SQL中GROUP BY语句来将数据集合成在一起是SQL中一种理想的使用。

    关于这一点,Python中的defaultdictCounter提供了很高效的实现。Python的实现版本非常高效,只是使用defaultdict对大量的行进行查询以及计算结果的归并,可能比在数据库中使用GROUP BY要快得多。

    如果有疑问,就测试一下。SQL数据库的支持者通常会给出无关紧要的观点。当被告知SQL应该会比Python快很多倍时,要得到证据。数据收集并不局限于使用一次性初始化的方式,即便对于很快可以完成的任务。随着空间使用的增加和变化,SQL 数据库和Python的对比结果也会改变。

    自己编写的访问层通常对于问题领域而言有着很强的特殊性。在性能上可能会有优势,并且在行和对象之间的映射也相对透明。不过每次类的改变或者数据库方面的改动会造成一些麻烦,这是一个缺陷。

    一个完善的ORM可能需要花一些时间来学习其中的功能,而它所带来的最大的好处是,长期的简化。学习ORM的功能会涉及最初的工作以及返工的教训。在设计上的初次尝试会带来原来在SQL框架中有效的功能需要被重做,这需要在实际中进行权衡和考虑。

    11.9.3 键和键的设计

    因为 SQL 依赖于键,必须在设计上考虑并为不同的对象进行键的管理。需要设计从对象到键的映射,用于标识对象。一种选择是查找一个属性(或属性的结合),它已经是主键并不能被改变。另一种方式是生成不能被改变的代理主键,而其他属性可以被改变。

    大部分关系数据库可以为我们生成代理主键,通常这是最好的做法。对于其他唯一属性或候选键属性,可以通过定义SQL索引来提高性能。

    必须考虑到对象间外键的关系。有常见的几种设计方式:1对多、多对1、多对多和可选的1对1。我们需要清晰地知道SQL是如何使用键来表示对象关系的,以及SQL查询是如何构建Python集合的。

    11.9.4 应用软件的层

    在使用sqlite3时,为了相对成熟的可用性,应用必须进行合理的分层。通常,可以看到分层的软件架构分为如下几个部分。

    • 表现层:这是最上层的用户界面,通常为网站或桌面GUI程序。
    • 应用层:这是内部服务或应用中的控制器。这部分可称为处理模型,与逻辑数据模型是不同的。
    • 业务逻辑层或问题领域模型层:这里是定义业务逻辑或问题模型的地方。这有时被称为逻辑数据模型。我们已经看了一个例子,如何使用一个微博和文章来构建模型。
    • 基础架构:这部分通常包括一些层和其他横切方面,例如日志、安全性和网络访问。
      • 数据访问层:它们是访问数据对象的协议或方法。通常是一个ORM层。我们已经介绍了SQLAlchemy,还有更多其他的选择。
      • 持久化层:这里是文件存储时所使用的物理数据模型。sqlite3模块实现了持久化。当使用类似SQLAlchemy的ORM时,只需要在创建引擎时对SQLite引用就可以了。

    在介绍本章的sqlite3和第10章“用Shelve保存和获取对象”时,可以看到熟练掌握面向对象编程会涉及一些更高层面上的设计模式。我们不能简单地将类设计为相互隔离的,但是需要在更高的层面了解类之间是如何组织的。

    11.9.5 展望

    在下一章中,我们会介绍如何使用REST来完成对象的传输和共享。这个设计模式会演示,如何管理状态的表示方式以及如何在进程间传输对象状态。我们将使用一些持久化模型来表示正在传输对象的状态。

    在第13章“配置文件和持久化”中,将介绍配置文件,也会介绍几种用于将控制应用程序的表示层数据表示进行持久化的方式。