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. 导入
ZODB
、
ZODB.FileStorage
和
transaction
模块。
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. 导入
ZODB
和
ZODB.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. 创建自定义类对象(
noah
和
jeremy
)。
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. 获取
noah
和
jeremy
账户对象。
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. 获取
noah
和
jeremy
账户对象。
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 数据持久化方面提供一些帮助和参考。
超级会员免费看

被折叠的 条评论
为什么被折叠?



