本节笔记试图记录一些些在 Python 中使用数据库的方法以及其它数据持久化的技巧。总的来说,本节笔记的针对性强,应该不至于像之前的笔记那样,知识点凌乱不堪。
>>> import dbm
>>> file = dbm.open('conf', 'c')
>>> file['user'] = 'user name'
>>> file['password'] = 'password'
>>> file['user']
b'user name'
>>> file.keys()
[b'password', b'user']
>>> len(file)
2
>>> file['website'] = 'http://blog.chriscabin.com'
>>> file['foo'] = 'bar'
>>> file.keys()
[b'website', b'password', b'user', b'foo']
>>> del file['foo']
>>> file.keys()
[b'website', b'password', b'user']
>>> file.close()
>>> file = dbm.open('conf', 'c)
>>> file.keys()
[b'website', b'password', b'user']
>>> for key in file.keys():
print('{} => {}'.format(key, file[key]))
b'website' => b'http://blog.chriscabin.com'
b'password' => b'password'
b'user' => b'user name'
dbm.whichdb
函数检测文件使用的是哪种实现创建的,这种检测是基于文件的内容进行的。dbm.bsd
, dbm.gnu
, dbm.ndbm
, dbm.dumb
的顺序来尝试查找这些接口。如果都不存在,则使用最后一个 Python 自带的实现dbm.dumb
,当然性能和健全性都不如其它实现。pickle
模块是一种超级通用的数据格式化和去格式化工具,几乎能把内存中任意的 Python 对象转换成字符串,以便存储在无格式的文件中,或者通过网络传输。这种行为叫做序列化。一些情况下是不能 pickle 的:
使用示例:
>>> import pickle
>>> conf = {"user": "user name", "password": "password"}
>>> pickle.dumps(conf)
b'\x80\x03}q\x00(X\x04\x00\x00\x00userq\x01X\t\x00\x00\x00user nameq\x02X\x08\x00\x00\x00passwordq\x03h\x03u.'
>>> pickle.dumps(conf, protocol=0)
b'(dp0\nVuser\np1\nVuser name\np2\nsVpassword\np3\ng3\ns.'
>>> x = pickle.dumps(conf)
>>> pickle.loads(x)
{'user': 'user name', 'password': 'password'}
>>> y = pickle.loads(x)
>>> y == conf, x is conf
(True, False)
shelve
是一种可以使用键来存储和检索任意 Python 对象的文件,并且是 Python 原生支持的。它是 DBM 和 pickle
的结合体:
shelve
模块会首先使用 pickle
模块将对象序列化,然后使用 DBM
模块根据键将对象字符串存储到 DBM 文件中;shelve
首先使用 dbm
模块取出键对应的字符串,然后使用pickle
模块将字符串反序列化为原始对象。shelve
继承了 dbm
的特性,导致它在可移植性上较差!
shelve
模块的简单使用例子,完整的代码参见 shelve_demo:def main():
database = shelve.open('demo_db.shelve')
# now, you can save anything to your disk.
database['stu'] = Student('Chris', 23, 2, 12345)
database['list'] = [x for x in range(10)]
# close it
database.close()
# reload database
database = shelve.open('demo_db.shelve')
# read all saved objects
for each in database.keys():
print('{} => {}'.format(each, database[each]))
# clear all
database.clear()
database.close()
# output
list => [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
stu => Name: Chris
Age: 23
Grade: 2
Card Id: 12345
shelve
的约束:
data[key].attr = value
的方式,而应当采用下面的方式
# 取回
obj = data[key]
obj.attr = value
# 写回去
data[key] = obj
shelve
文件写入,否则可能会损坏数据。shelve
更强大的选择。虽然 ZODB 不支持 SQL,但是ZODB存储的对象可以利用 Python 的全部威力。ZODB 重要特性:
Persistent
超类对象,如果属性变动,则会自动更新。shelve
中 DBM 文件具体实现的差别。给 Python 3 安装 ZODB:sudo pip3 install ZODB
。
# `FileStorage` 实际上是将一个数据库映射到无格式文本文件的代理对象。
# 使用 ZODB 的一般步骤
self._storage = FileStorage.FileStorage(db_file)
self._db = DB(self._storage)
self._root = self._db.open().root()
# 存储对象
stuff_db.root['foo1'] = 'foo bar hello, world'
stuff_db.root['foo2'] = {'hello': 'world'}
stuff_db.root['foo3'] = [[1, 2, 3, 4], 'hello']
# 事务提交,然后存储到文件中,最后可以关闭数据库
transaction.commit()
self._storage.close()
# 输出结果:
foo2 => {'hello': 'world'}
foo1 => foo bar hello, world
foo3 => [[1, 2, 3, 4], 'hello']
foo2 => {'hello': 'world'}
foo1 => foo bar hello, world
foo3 => [[1, 2, 3, 4], 'hello']
foo2 => {'hello': 'world'}
foo1 => Boy
foo3 => [[1, 2, 3, 4], 'hello']
# 生成的文件:stuff.fs, stuf.fs.index, stuff.fs.lock, stuff.fs.tmp
在数据库 API 中, Python 中的 SQL 数据库基于下面三个概念:
此外,数据库 API 还定义了一套数据库异常类型的标准集合,特殊的数据库类型对象构造器,以及顶级信息查看调用,包括线程安全和风格替换检查。
使用方式 | 说明 |
---|---|
conn = connect("username/password") |
登录数据库服务器,并返回一个连接对象 |
conn.close() |
关闭数据库连接 |
conn.commit() |
提交事务 |
conn.rollback() |
回滚未决定的事务 |
cursor = conn.cursor() |
获取游标对象,这样你就可以执行 SQL 了。 |
cursor.execute(sqlstr, [, params]) |
执行 SQL 语句。运行后,游标的rowcount 属性返回更改的行数等。description 首先可以记录表中的字段名称和字段属性。 |
cursor.fetchone() , cursor.fetchmany([size]) , cursor.fetchall() |
获取查询结果 |
- 演示使用 Python 数据库 API 的基本方法示例参见 sqlite_demo.py。在这个示例中,简要介绍了以下几种操作(主要还是需要熟悉 SQL):
- 与sqlite数据库连接,并创建数据库表;
- 演示如何插入记录的三种方法;
- 如何进行查询操作;
- 如何进行记录的更新;
- 如何删除记录。
- 查询后的结果是一个元组,不方便我们使用。所以,一个比较简单的方法是,将返回的结果转换成字典,详细的代码示例参见 sqlite_advance.py:
# 获取列名
col_names = [x[0] for x in cursor.description]
# 获取一行
row = cursor.fetchone()
# 打包成字典
dict_result = dict(zip(col_names, row))