news 2026/2/6 11:19:31

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/2/2 23:34:57

38、Python编程实用指南:从基础到高级应用

Python编程实用指南&#xff1a;从基础到高级应用1. 回调函数与函数对象回调函数和函数传递的概念可能对一些人来说比较陌生&#xff0c;但深入了解它是很有价值的。在Python中&#xff0c;函数是“一等公民”&#xff0c;这意味着可以像操作对象一样传递和处理函数&#xff0c…

作者头像 李华
网站建设 2026/2/5 12:17:47

460. LFU 缓存

问题描述&#xff1a; 请你为 最不经常使用&#xff08;LFU&#xff09;缓存算法设计并实现数据结构。 实现 LFUCache 类&#xff1a; LFUCache(int capacity) - 用数据结构的容量 capacity 初始化对象int get(int key) - 如果键 key 存在于缓存中&#xff0c;则获取键的值&…

作者头像 李华
网站建设 2026/2/2 23:23:38

Betaflight 2025.12性能突破:智能飞控固件的全方位升级指南

Betaflight 2025.12性能突破&#xff1a;智能飞控固件的全方位升级指南 【免费下载链接】betaflight Open Source Flight Controller Firmware 项目地址: https://gitcode.com/gh_mirrors/be/betaflight 穿越机爱好者们翘首以盼的Betaflight 2025.12版本正式发布&#x…

作者头像 李华
网站建设 2026/2/4 17:23:51

42、Xenomai实时系统:从传统RTOS迁移到Linux的解决方案

Xenomai实时系统:从传统RTOS迁移到Linux的解决方案 1. Xenomai简介 Xenomai是一个实时子系统,能与Linux内核紧密集成,为应用程序提供可预测的响应时间。它基于双内核方法,一个小的协内核与Linux在同一硬件上并行运行。在主机内核支持内存管理单元(MMU)保护时,Xenomai支…

作者头像 李华
网站建设 2026/2/4 18:00:41

43、深入了解Xenomai实时系统

深入了解Xenomai实时系统 1. 核心代码分析 以下是一段关键代码,其主要功能是等待消息并处理超时和中断情况: task = vrtx_current_task(); /** Set up a few status bits the VRTX way, so that inquiries* about the task state will return proper information.*/ task-…

作者头像 李华
网站建设 2026/2/6 4:06:02

基于51单片机的蓝牙智能台灯设计

基于51单片机的蓝牙智能台灯设计 &#xff08;程序&#xff0b;原理图&#xff0b;设计报告&#xff09; 功能介绍 具体功能&#xff1a; 1、当人靠近时&#xff0c;灯亮起&#xff0c;如果人靠得太近&#xff0c;蜂鸣器会发出警报&#xff0c;一段时间后如果没有人&#xff…

作者头像 李华