文章大纲
如果要自动支持数据并发访问,允许多用户同时读写磁盘且不会导致文件损坏之类的问题,还希望能支持通过多个字段或属性进行复杂的搜索,这些需求通过纯文本的方式很难实现,此时使用标准的数据库是个好选择。
Python 数据库 API
有多种 SQL 数据库,同时也有很多对应的 Python 数据库客户端模块,为了解决模块之间接口的差异,定义了一个标准数据库 API。
全局变量
所有与 DB API 2.0 兼容的数据库模块都必须包含三个全局变量,描述了模块的特征。
全局变量:
apilevel
:使用的 Python DB API 版本threadsafety
:模块的线程安全程度如何paramstyle
:在SQL查询中使用哪种参数风格
异常
DB API 定义了多种异常。
异常 | 超类 | 描述 |
---|---|---|
StandardError | 所有异常的超类 | |
Warning | StandardError | 发生非致命问题时引发 |
Error | StandardError | 所有错误条件的超类 |
InterfaceError | Error | 与接口(而不是数据库)相关的错误 |
DatabaseError | Error | 与数据库相关的错误的超类 |
DataError | DatabaseError | 与数据相关的问题,如值不在合法的范围内 |
OperationalError | DatabaseError | 数据库操作内部的错误 |
IntegrityError | DatabaseError | 关系完整性遭到破坏,如键未通过检查 |
InternalError | DatabaseError | 数据库内部的错误,如游标无效 |
ProgrammingError | DatabaseError | 用户编程错误,如未找到数据库表 |
NotSupportedError | DatabaseError | 请求不支持的功能,如回滚 |
连接和游标
要使用数据库,必须先连接到它,使用 connect
函数。
函数接受多个参数,取决于使用哪种数据库。
参数名 | 描述 | 是否可选 |
---|---|---|
dns | 数据源名称,具体含义随数据库而异 | 否 |
user | 用户名 | 是 |
password | 密码 | 是 |
host | 主机名 | 是 |
database | 数据库名称 | 是 |
函数 connect
返回一个连接对象,表示当前到数据库的会话。
连接对象支持以下方法:
方法名 | 描述 |
---|---|
close() | 关闭连接对象。之后,连接对象及其游标将不可用 |
commit() | 提交未提交的事务——如果支持的话;否则什么都不做 |
rollback() | 回滚未提交的事务(可能不可用) |
cursor() | 返回连接的游标对象 |
游标对象支持的方法比连接多。
游标对象的方法:
名称 | 描述 |
---|---|
callproc(name[, params]) | 使用指定的参数调用指定的数据库过程(可选) |
close() | 关闭游标。关闭后游标不可用 |
execute(oper[, params]) | 执行一个SQL操作——可能指定参数 |
executemany(oper, pseq) | 执行指定的SQL操作多次,每次都序列中的一组参数 |
fetchone() | 以序列的方式取回查询结果中的下一行;如果没有更多的行,就返回None |
fetchmany([size]) | 取回查询结果中的多行,其中参数size的值默认为arraysize |
fetchall() | 以序列的序列的方式取回余下的所有行 |
nextset() | 跳到下一个结果集,这个方法是可选的 |
setinputsizes(sizes) | 用于为参数预定义内存区域 |
setoutputsize(size[, col]) | 为取回大量数据而设置缓冲区长度 |
游标对象的属性:
名称 | 描述 |
---|---|
description | 由结果列描述组成的序列(只读) |
rowcount | 结果包含的行数(只读) |
arraysize | fetchmany返回的行数,默认为1 |
类型
为了能够与底层 SQL 数据库正确的对接,DB API 定义了一些构造函数和常量,用于提供特殊的类型和值。
DB API 构造函数和特殊值:
名称 | 描述 |
---|---|
Date(year, month, day) | 创建包含日期值的对象 |
Time(hour, minute, second) | 创建包含时间值的对象 |
Timestamp(y, mon, d, h, min, s) | 创建包含时间戳的对象 |
DateFromTicks(ticks) | 根据从新纪元开始过去的秒数创建包含日期值的对象 |
TimeFromTicks(ticks) | 根据从新纪元开始过去的秒数创建包含时间值的对象 |
imestampFromTicks(ticks) | 根据从新纪元开始过去的秒数创建包含时间戳的对象 |
Binary(string) | 创建包含二进制字符串值的对象 |
STRING | 描述基于字符串的列(如CHAR) |
BINARY | 描述二进制列(如LONG或RAW) |
NUMBER | 描述数字列 |
DATETIME | 描述日期/时间列 |
ROWID | 描述行ID列 |
并不是所有的模块都遵循上述的构造函数。
SQLite 和 PySQLite
Python 标准库内置 sqlite3
模块,实现对 SQLite 数据库的操作。
基本使用
要使用 Python 标准库中的 SQLite,首先需要导入 sqlite3
模块,然后创建到数据库文件的连接。
>>> import sqlite3
>>> conn = sqlite3.connect('demo.db')
>>> curs = conn.cursor()
只需提供一个文件名,如果指定的文件不存在将自动创建。
连接到数据后,就可以使用 cursor()
方法获取到游标。
游标可以用于执行 SQL 查询,如果修改了数据,务必通过 commit()
来提交修改。
调用 close()
方法来关闭数据库连接。
>>> conn.commit()
>>> conn.close()
数据库应用程序示例
使用现有的文件导入到 SQLite 数据库中:
import sqlite3
#数据参考格式
#~18226~^~CRACKERS,RYE,WAFERS,PLAIN~^5.00^334^9.60^0.90^4.10^80.40^22.9^1.01^40^5.94^121^334^495^557^2.80^0.461^5.366^23.8^0.1^0.427^0.289^1.581^0.569^0.271^45^0^45^45^20.0^0.00^5^0^0^1^2^0^0^245^0.80^0.0^0^5.7^0.108^0.152^0.397^0^14.2^~.5 oz~^61^~1 cup, crushed~^0
def convert(value):
if value.startswith('~'):
return value.strip('~')
if not value:
value = '0'
return float(value)
conn = sqlite3.connect('food.db')
curs = conn.cursor()
curs.execute('''
CREATE TABLE food (
id TEXT PRIMARY KEY,
desc TEXT,
water FLOAT,
kcal FLOAT,
protein FLOAT,
fat FLOAT,
ash FLOAT,
carbs FLOAT,
fiber FLOAT,
sugar FLOAT
)
''')
query = 'INSERT INTO food VALUES(?,?,?,?,?,?,?,?,?,?)'
field_count = 10
for line in open('ABBREV.txt'):
fields = line.split('^')
vals = [convert(f) for f in fields[:field_count]]
curs.execute(query, vals)
conn.commit()
conn.close()
搜索并处理结果程序示例:
import sqlite3, sys
conn = sqlite3.connect('food.db')
curs = conn.cursor()
query = 'SELECT * FROM food WHERE ' + sys.argv[1]
print(query)
curs.execute(query)
names = [f[0] for f in curs.description]
for row in curs.fetchall():
for pair in zip(names, row):
print('{}: {}'.format(*pair))
print()
执行效果:
python food_query.py "kcal <= 100 AND fiber >= 10 ORDER BY sugar limit 1"
SELECT * FROM food WHERE kcal <= 100 AND fiber >= 10 ORDER BY sugar limit 1
id: 09216
desc: ORANGE PEEL,RAW
water: 72.5
kcal: 97.0
protein: 1.5
fat: 0.2
ash: 0.8
carbs: 25.0
fiber: 10.6
sugar: 0.0