news 2026/4/16 11:14:00

34、Python 数据持久化:从简单到关系型序列化的全面指南

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
34、Python 数据持久化:从简单到关系型序列化的全面指南

Python 数据持久化:从简单到关系型序列化的全面指南

1. 简单序列化:ZODB 的使用

1.1 ZODB 简介

ZODB(Zope Object Database)是一个用于序列化数据的模块。它的简单使用方式与 pickle 或 YAML 类似,但具有可扩展性,能满足更多需求,例如提供事务支持,还可使用 ZEO 作为分布式对象存储。虽然它也可用于关系型持久化,但在一些基础示例中,更像 shelve,因此这里将其归为简单持久化的范畴。

1.2 安装 ZODB

安装 ZODB 很简单,使用easy_install ZODB3命令即可。easy_install会自动解决 ZODB 模块的依赖问题,下载并安装所需的一切。

1.3 简单使用示例

以下是一个将字典和列表序列化到 ZODB 数据库的示例代码:

#!/usr/bin/env python import ZODB import ZODB.FileStorage import transaction filestorage = ZODB.FileStorage.FileStorage('zodb_filestorage.db') db = ZODB.DB(filestorage) conn = db.open() root = conn.root() root['list'] = ['this', 'is', 'a', 'list'] root['dict'] = {'this': 'is', 'a': 'dictionary'} transaction.commit() conn.close()

操作步骤如下:
1. 导入ZODBZODB.FileStoragetransaction模块。
2. 创建FileStorage对象,指定数据库文件。
3. 创建DB对象并连接到FileStorage对象。
4. 打开数据库并获取根节点。
5. 向根节点添加数据结构(列表和字典)。
6. 使用transaction.commit()提交更改。
7. 关闭数据库连接。

1.4 读取数据示例

以下是从 ZODB 数据库中读取数据的示例代码:

#!/usr/bin/env python import ZODB import ZODB.FileStorage filestorage = ZODB.FileStorage.FileStorage('zodb_filestorage.db') db = ZODB.DB(filestorage) conn = db.open() root = conn.root() print root.items() conn.close()

操作步骤如下:
1. 导入ZODBZODB.FileStorage模块。
2. 创建FileStorage对象,指定数据库文件。
3. 创建DB对象并连接到FileStorage对象。
4. 打开数据库并获取根节点。
5. 打印根节点的所有项。
6. 关闭数据库连接。

1.5 序列化自定义类示例

以下是自定义类Account的定义:

#!/usr/bin/env python import persistent class OutOfFunds(Exception): pass class Account(persistent.Persistent): def __init__(self, name, starting_balance=0): self.name = name self.balance = starting_balance def __str__(self): return "Account %s, balance %s" % (self.name, self.balance) def __repr__(self): return "Account %s, balance %s" % (self.name, self.balance) def deposit(self, amount): self.balance += amount return self.balance def withdraw(self, amount): if amount > self.balance: raise OutOfFunds self.balance -= amount return self.balance

以下是将自定义类对象序列化到 ZODB 数据库的示例代码:

#!/usr/bin/env python import ZODB import ZODB.FileStorage import transaction import custom_class_zodb filestorage = ZODB.FileStorage.FileStorage('zodb_filestorage.db') db = ZODB.DB(filestorage) conn = db.open() root = conn.root() noah = custom_class_zodb.Account('noah', 1000) print noah root['noah'] = noah jeremy = custom_class_zodb.Account('jeremy', 1000) print jeremy root['jeremy'] = jeremy transaction.commit() conn.close()

操作步骤如下:
1. 导入所需模块。
2. 创建FileStorage对象和DB对象,打开数据库并获取根节点。
3. 创建自定义类对象(noahjeremy)。
4. 将对象添加到根节点。
5. 提交更改并关闭数据库连接。

1.6 数据库操作流程图

graph TD; A[导入模块] --> B[创建FileStorage对象]; B --> C[创建DB对象并连接]; C --> D[打开数据库并获取根节点]; D --> E{操作类型}; E -- 写入数据 --> F[添加数据到根节点]; F --> G[提交更改]; G --> H[关闭数据库连接]; E -- 读取数据 --> I[打印根节点数据]; I --> H;

1.7 账户数据转移示例

以下是从noah账户向jeremy账户转移 300 的示例代码:

#!/usr/bin/env python import ZODB import ZODB.FileStorage import transaction import custom_class_zodb filestorage = ZODB.FileStorage.FileStorage('zodb_filestorage.db') db = ZODB.DB(filestorage) conn = db.open() root = conn.root() noah = root['noah'] print "BEFORE WITHDRAWAL" print "=================" print noah jeremy = root['jeremy'] print jeremy print "-----------------" transaction.begin() noah.withdraw(300) jeremy.deposit(300) transaction.commit() print "AFTER WITHDRAWAL" print "================" print noah print jeremy print "----------------" conn.close()

操作步骤如下:
1. 导入所需模块。
2. 创建FileStorage对象和DB对象,打开数据库并获取根节点。
3. 获取noahjeremy账户对象。
4. 打印转账前的账户信息。
5. 开始事务。
6. 从noah账户取款,向jeremy账户存款。
7. 提交事务。
8. 打印转账后的账户信息。
9. 关闭数据库连接。

1.8 循环转账示例

以下是一个循环从noah账户向jeremy账户转账 300,直到余额不足的示例代码:

#!/usr/bin/env python import ZODB import ZODB.FileStorage import transaction import custom_class_zodb filestorage = ZODB.FileStorage.FileStorage('zodb_filestorage.db') db = ZODB.DB(filestorage) conn = db.open() root = conn.root() noah = root['noah'] print "BEFORE TRANSFER" print "===============" print noah jeremy = root['jeremy'] print jeremy print "-----------------" while True: try: transaction.begin() jeremy.deposit(300) noah.withdraw(300) transaction.commit() except custom_class_zodb.OutOfFunds: print "OutOfFunds Error" print "Current account information:" print noah print jeremy transaction.abort() break print "AFTER TRANSFER" print "==============" print noah print jeremy print "----------------" conn.close()

操作步骤如下:
1. 导入所需模块。
2. 创建FileStorage对象和DB对象,打开数据库并获取根节点。
3. 获取noahjeremy账户对象。
4. 打印转账前的账户信息。
5. 进入循环,开始事务。
6. 从noah账户取款,向jeremy账户存款。
7. 提交事务。
8. 如果出现OutOfFunds异常,打印错误信息和当前账户信息,中止事务并跳出循环。
9. 打印转账后的账户信息。
10. 关闭数据库连接。

2. 关系型序列化

2.1 关系型序列化概述

简单序列化有时可能不够,需要关系型分析的能力。关系型序列化指的是将 Python 对象序列化并与其他 Python 对象建立关系,或者将关系型数据存储在关系型数据库中,并提供类似 Python 对象的接口来访问这些数据。

2.2 SQLite

2.2.1 SQLite 简介

根据 SQLite 官网的描述,SQLite 是一个实现了自包含、无服务器、零配置、事务性 SQL 数据库引擎的软件库。它的数据库引擎与代码在同一进程中运行,数据存储在一个文件中,无需配置主机名、端口、用户名、密码等信息,使用方便,且大多数主流操作系统和编程语言都支持它。

2.2.2 创建数据库

假设我们有一个名为inventory.sql的文件,包含以下表定义:

BEGIN; CREATE TABLE "inventory_ipaddress" ( "id" integer NOT NULL PRIMARY KEY, "address" text NULL, "server_id" integer NOT NULL ); CREATE TABLE "inventory_hardwarecomponent" ( "id" integer NOT NULL PRIMARY KEY, "manufacturer" varchar(50) NOT NULL, "type" varchar(50) NOT NULL, "model" varchar(50) NULL, "vendor_part_number" varchar(50) NULL, "description" text NULL ); CREATE TABLE "inventory_operatingsystem" ( "id" integer NOT NULL PRIMARY KEY, "name" varchar(50) NOT NULL, "description" text NULL ); CREATE TABLE "inventory_service" ( "id" integer NOT NULL PRIMARY KEY, "name" varchar(50) NOT NULL, "description" text NULL ); CREATE TABLE "inventory_server" ( "id" integer NOT NULL PRIMARY KEY, "name" varchar(50) NOT NULL, "description" text NULL, "os_id" integer NOT NULL REFERENCES "inventory_operatingsystem" ("id") ); CREATE TABLE "inventory_server_services" ( "id" integer NOT NULL PRIMARY KEY, "server_id" integer NOT NULL REFERENCES "inventory_server" ("id"), "service_id" integer NOT NULL REFERENCES "inventory_service" ("id"), UNIQUE ("server_id", "service_id") ); CREATE TABLE "inventory_server_hardware_component" ( "id" integer NOT NULL PRIMARY KEY, "server_id" integer NOT NULL REFERENCES "inventory_server" ("id"), "hardwarecomponent_id" integer NOT NULL REFERENCES "inventory_hardwarecomponent" ("id"), UNIQUE ("server_id", "hardwarecomponent_id") ); COMMIT;

可以使用以下命令创建 SQLite 数据库:

jmjones@dinkgutsy:~/code$ sqlite3 inventory.db < inventory.sql

不同系统的安装方式如下:
| 系统类型 | 安装命令 |
| ---- | ---- |
| Ubuntu 和 Debian | apt-get install sqlite3 |
| Red Hat | yum install sqlite |
| 其他 Linux 发行版、UNIX 或 Windows | 从 http://www.sqlite.org/download.html 下载源码或预编译二进制文件 |

2.2.3 连接数据库并插入数据

以下是连接到 SQLite 数据库并插入数据的示例代码:

import sqlite3 conn = sqlite3.connect('inventory.db') cursor = conn.execute("insert into inventory_operatingsystem (name, description) values ('Linux', '2.0.34 kernel');") cursor.fetchall() conn.commit()

操作步骤如下:
1. 导入sqlite3模块。
2. 使用connect()方法连接到数据库。
3. 执行插入数据的 SQL 语句,获取游标对象。
4. 调用fetchall()方法获取结果集(插入操作无结果集)。
5. 提交更改。

2.2.4 读取数据

以下是从 SQLite 数据库中读取数据的示例代码:

import sqlite3 conn = sqlite3.connect('inventory.db') cursor = conn.execute('select * from inventory_operatingsystem;') result = cursor.fetchall() print result

操作步骤如下:
1. 导入sqlite3模块。
2. 使用connect()方法连接到数据库。
3. 执行查询语句,获取游标对象。
4. 调用fetchall()方法获取结果集。
5. 打印结果集。

2.3 Storm ORM

2.3.1 ORM 概述

ORM(Object-Relational Mapping)是一种将数据库中的数据以面向对象的方式表示的趋势。在 ORM 中,编程语言中的对象可以对应数据库中单个表的一行,通过外键关系连接的表甚至可以作为对象的属性访问。

2.3.2 Storm ORM 简介

Storm 是由 Canonical 公司开源的 ORM,虽然在 Python 数据库领域是相对较新的工具,但已经有了一定的用户群体,有望成为领先的 Python ORM 之一。

2.3.3 创建映射

以下是将 Python 类OperatingSystem映射到inventory_operatingsystem表的示例代码:

import storm.locals class OperatingSystem(object): __storm_table__ = 'inventory_operatingsystem' id = storm.locals.Int(primary=True) name = storm.locals.Unicode() description = storm.locals.Unicode()

在这个类定义中,__storm_table__属性指定了要访问的表名,类属性会自动映射到表中同名的列。如果不想将description属性映射到description列,可以使用name关键字参数,例如:

dsc = storm.locals.Unicode(name='description')
2.3.4 插入数据

以下是向inventory_operatingsystem表中插入数据的示例代码:

import storm.locals import storm_model import os operating_system = storm_model.OperatingSystem() operating_system.name = u'Windows' operating_system.description = u'3.1.1' db = storm.locals.create_database('sqlite:///%s' % os.path.join(os.getcwd(), 'inventory.db')) store = storm.locals.Store(db) store.add(operating_system) store.commit()

操作步骤如下:
1. 导入所需模块。
2. 创建OperatingSystem对象并设置属性值。
3. 创建数据库对象。
4. 创建Store对象。
5. 将对象添加到Store中。
6. 提交更改。

2.3.5 读取数据

以下是从inventory_operatingsystem表中读取数据的示例代码:

import storm.locals import storm_model import os db = storm.locals.create_database('sqlite:///%s' % os.path.join(os.getcwd(), 'inventory.db')) store = storm.locals.Store(db) for o in store.find(storm_model.OperatingSystem): print o.id, o.name, o.description

操作步骤如下:
1. 导入所需模块。
2. 创建数据库对象。
3. 创建Store对象。
4. 使用find()方法查找所有OperatingSystem对象。
5. 遍历对象并打印属性值。

2.4 Storm ORM 操作流程图

graph TD; A[导入模块] --> B[创建数据库对象]; B --> C[创建Store对象]; C --> D{操作类型}; D -- 写入数据 --> E[创建对象并设置属性]; E --> F[将对象添加到Store]; F --> G[提交更改]; D -- 读取数据 --> H[使用find()方法查找对象]; H --> I[遍历对象并打印属性];

综上所述,Python 提供了多种数据持久化的方法,从简单的序列化到关系型序列化,每种方法都有其优缺点,可以根据具体需求选择合适的方法。

3. 不同数据持久化方法对比

3.1 功能对比

方法简单序列化关系型序列化
适用场景仅需简单保存和存储 Python 对象供后续使用需要进行关系型分析,处理复杂数据关系
数据结构支持支持基本数据类型和自定义类对象的序列化支持将 Python 对象与数据库表关联,处理表间关系
高级特性如 ZODB 提供事务支持,但整体功能相对简单支持 SQL 查询、表连接、数据更新等复杂操作

3.2 性能对比

方法读写速度数据规模适应性
简单序列化(如 ZODB)读写速度较快,适用于小规模数据随着数据规模增大,性能可能下降,不适合超大规模数据存储
关系型序列化(如 SQLite + Storm ORM)读写速度相对较慢,但可通过 SQL 优化能较好地适应大规模数据,支持复杂查询和事务处理

3.3 代码复杂度对比

方法代码量学习成本
简单序列化(如 ZODB)代码相对较少,基本操作简单学习曲线较平缓,容易上手
关系型序列化(如 SQLite + Storm ORM)代码量较多,涉及 SQL 语句和 ORM 映射学习成本较高,需要掌握 SQL 和 ORM 相关知识

4. 实际应用案例分析

4.1 简单序列化的应用案例

假设我们正在开发一个小型的桌面应用程序,需要保存用户的配置信息,如用户的偏好设置、最近打开的文件列表等。这些信息结构简单,且不需要进行复杂的关系型分析。此时,使用简单序列化方法(如 ZODB)是一个不错的选择。

以下是一个简单的示例代码,用于保存用户的偏好设置:

import ZODB import ZODB.FileStorage import transaction # 创建 FileStorage 对象 filestorage = ZODB.FileStorage.FileStorage('user_config.db') db = ZODB.DB(filestorage) conn = db.open() root = conn.root() # 定义用户偏好设置 user_preferences = { 'theme': 'dark', 'font_size': 12, 'auto_save': True } # 将偏好设置保存到 ZODB 数据库 root['user_preferences'] = user_preferences transaction.commit() # 读取用户偏好设置 saved_preferences = root['user_preferences'] print(saved_preferences) # 关闭数据库连接 conn.close()

操作步骤如下:
1. 导入所需的 ZODB 模块。
2. 创建FileStorage对象和DB对象,打开数据库并获取根节点。
3. 定义用户偏好设置的字典。
4. 将字典添加到根节点,并提交更改。
5. 从根节点读取保存的偏好设置并打印。
6. 关闭数据库连接。

4.2 关系型序列化的应用案例

考虑一个企业级的库存管理系统,需要管理多个表之间的关系,如服务器信息、操作系统信息、服务信息等。此时,使用关系型序列化方法(如 SQLite + Storm ORM)可以更好地处理这些复杂的关系。

以下是一个使用 Storm ORM 进行库存管理系统操作的示例代码:

import storm.locals import storm_model import os # 创建数据库对象 db = storm.locals.create_database('sqlite:///%s' % os.path.join(os.getcwd(), 'inventory.db')) store = storm.locals.Store(db) # 插入新的服务器信息 server = storm_model.Server() server.name = 'Server01' server.description = 'Main server for the company' server.os_id = 1 # 假设操作系统 ID 为 1 # 将服务器信息添加到数据库 store.add(server) store.commit() # 查询所有服务器信息 servers = store.find(storm_model.Server) for s in servers: print(s.id, s.name, s.description) # 关闭 Store store.close()

操作步骤如下:
1. 导入所需的 Storm ORM 模块。
2. 创建数据库对象和Store对象。
3. 创建Server对象并设置属性值。
4. 将Server对象添加到Store中,并提交更改。
5. 使用find()方法查询所有Server对象,并遍历打印属性值。
6. 关闭Store

5. 总结与建议

5.1 总结

Python 提供了丰富的数据持久化方法,包括简单序列化和关系型序列化。简单序列化方法(如 ZODB)适用于简单的数据存储需求,代码简单,学习成本低;关系型序列化方法(如 SQLite + Storm ORM)适用于处理复杂的关系型数据,支持 SQL 查询和事务处理,但代码复杂度和学习成本相对较高。

5.2 建议

在选择数据持久化方法时,可以根据以下因素进行考虑:
-数据复杂度:如果数据结构简单,不需要进行复杂的关系型分析,建议使用简单序列化方法;如果数据关系复杂,需要进行 SQL 查询和事务处理,建议使用关系型序列化方法。
-数据规模:对于小规模数据,简单序列化方法通常可以满足需求;对于大规模数据,关系型序列化方法更具优势。
-开发团队技术水平:如果开发团队对 SQL 和 ORM 知识掌握较少,简单序列化方法更容易上手;如果团队具备相关技术能力,关系型序列化方法可以更好地发挥其优势。

5.3 未来展望

随着 Python 在数据处理和应用开发领域的不断发展,数据持久化技术也将不断完善和创新。未来可能会出现更多高效、易用的数据持久化工具和框架,为开发者提供更多的选择。同时,数据安全和性能优化也将成为数据持久化领域的重要研究方向。

5.4 实际应用流程图

graph TD; A[确定需求] --> B{数据复杂度}; B -- 简单 --> C[选择简单序列化方法]; B -- 复杂 --> D[选择关系型序列化方法]; C --> E[开发应用程序]; D --> F[设计数据库表结构]; F --> G[使用 ORM 进行映射]; E --> H[测试与部署]; G --> H;

通过对不同数据持久化方法的学习和实践,开发者可以根据具体需求选择最合适的方法,提高开发效率和应用程序的性能。希望本文能为大家在 Python 数据持久化方面提供一些帮助和参考。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/16 10:44:46

AutoCAD字体管理终极方案:彻底解决字体缺失的技术革命

AutoCAD字体管理终极方案&#xff1a;彻底解决字体缺失的技术革命 【免费下载链接】FontCenter AutoCAD自动管理字体插件 项目地址: https://gitcode.com/gh_mirrors/fo/FontCenter 在工程设计领域&#xff0c;AutoCAD字体管理一直是困扰设计师的技术难题。当您打开一份…

作者头像 李华
网站建设 2026/4/16 9:01:27

LobeChat新手引导教程生成

LobeChat 技术深度解析&#xff1a;从架构设计到实战落地 在大模型应用如雨后春笋般涌现的今天&#xff0c;一个关键问题逐渐浮现&#xff1a;我们有了强大的AI引擎&#xff0c;但用户真的愿意用吗&#xff1f; 很多开发者手握 GPT、Claude 或本地部署的 Llama 模型&#xff0c…

作者头像 李华
网站建设 2026/4/16 9:00:56

LobeChat GitHub星标增长趋势分析:未来是否会成为主流?

LobeChat&#xff1a;开源AI聊天界面的崛起之路 在生成式AI浪潮席卷全球的今天&#xff0c;一个有趣的现象正在发生&#xff1a;越来越多的开发者不再满足于直接使用ChatGPT这类“黑箱”产品&#xff0c;而是希望拥有更灵活、更可控的交互入口。他们想要的不只是对话能力——而…

作者头像 李华
网站建设 2026/4/16 9:01:34

LobeChat自动化运维脚本生成

LobeChat自动化运维脚本生成 在AI应用快速普及的今天&#xff0c;越来越多开发者希望将大语言模型&#xff08;LLM&#xff09;能力以直观方式呈现给终端用户。然而现实是&#xff1a;尽管后端模型日益强大&#xff0c;前端交互体验却常常成为“最后一公里”的瓶颈。命令行调用…

作者头像 李华
网站建设 2026/4/16 9:01:00

LobeChat季节性营销内容生成

LobeChat季节性营销内容生成 在电商大促、节日促销轮番登场的今天&#xff0c;市场团队常常面临一个尴尬局面&#xff1a;创意还没写完&#xff0c;活动已经开始了。传统的文案生产模式依赖人工反复打磨&#xff0c;不仅耗时耗力&#xff0c;还容易陷入“灵感枯竭—加班赶工—质…

作者头像 李华