数据库支持

数据并发访问:想让几个用户同时对基于磁盘的数据进行读写而不造成任何文件损坏。或者同时使用多个数据字段或属性进行复杂的搜索。
数据库——数据量巨大而同时还希望其他程序员容易理解。
本章会对Python的数据库编程接口进行讨论,这是一种连接SQL数据库的方法;同时也会展示如何通过API执行一些基本的SQL命令。

Python数据库编程接口(API)

在提供相同功能的不同模块之间进行切换时的问题通常是它们的接口(API)不同。为了解决Python中各种数据库模块间的兼容问题,通过一个标准的数据库编程接口(DB API)。

全局变量

如果想让程序同时应用于几个数据库,比较现实的做法是检查这些变量,看看给定的数据库模块是否能被程序接受。如果不能,就显示合适的错误信息然后退出。

变量名 用途
apilevel 所使用的的Python DB API版本
threadsafety 模块的线程安全等级
paramstyle 在SQL查询中使用的参数风格

API级别(apilevel)是个字符串常量,提供正在使用的API版本号。
线程安全性等级(trheadsafety)是个取值范围为0~3的整数。0表示线程完全不共享模块,而3表示模块是完全线程安全的。1表示线程本身可以共享模块,但不对连接共享。不使用多线程,完全不用担心这个变量。
参数风格(paramstyle)表示在执行多次类似查询的时候,参数是如何被拼接到SQL查询中的。

异常

API中定义了一些异常类,以便尽可能进行错误处理。

异常 超类 描述
StandardError 所有异常的泛型基类
Warning StandardError 非致命错误发生时引发
Error StandardError 所有错误条件的泛型超类
InterfaceError Error 关于接口而非数据库的错误
DatabaseError Error 与数据库相关的错误的基类
DataError DatabaseError 与数据库相关的问题,比如值超出范围
OperationalError DatabaseError 数据库内部操作错误
IntegrityError DatabaseError 关系完整性收到影响,比如键检查失败
InternalError DatabaseError 数据库内部错误没比如非法游标
ProgrammingError DatabaseError 用户编程错误,比如未找到表
NotSupportedError DatabaseError 请求不支持的特性(比如回滚)

连接和游标

为了使用底层的数据库系统,首先必须连接到它。
connect函数的常用参数

参数名 描述 是否可选
dsn 数据源名称,给出该参数表示数据库依赖
user 用户名
password 用户密码
host 主机名
database 数据库名

connect函数返回连接对象——表示目前的和数据库的会话。
连接对象方法

方法名 描述
close() 关闭连接之后,连接对象和它的游标均不可用
commit() 如果支持的话就提交挂起的事务,否则不做任何事
rollback() 回滚挂起的事务(可能不可用)
cursor() 返回连接的游标对象

rollback方法可能不可用,因为不是所有的数据库都支持事务(事务是一些列动作)。
游标对象——通过游标执行SQL查询并检查结果

类型

DB API 构造函数和特殊值

名称 描述
Data(year, month, day) 创建保存日期值的对象
Time(hour, minute, second) 创建保存时间值得对象
Timestamp(y, mon, d, h, min, s) 创建保存时间戳值得对象
DataFromTicks(ticks) 创建保存自新纪元以来的秒数对象
TimeFromTicks(ticks) 创建保存来自秒数的时间值的对象
TimestampFromTicks(ticks) 创建保存来自秒数的时间戳值得对象
Binary(string) 创建保存二进制字符串值的对象
STRING 描述基于字符串的列类型(比如CHAR)
BINARY 描述二进制列(比如LONG或RAW)
NUMBER 描述数字列
DATETIME 描述日期/时间列
ROWID 描述行ID列

SQLite和PySQLite

可用的SQL数据库引擎有很多,且都有相应的python模块。

入门

可以将SQLite作为一个模块导入,模块名称为sqlite3(标准库中的模块)。之后就可以创建一个到数据库文件的连接——如果文件不存在就自动生成——通过提供一个文件名(可以是文件的绝对路径或者相对路径):

>>> import sqlite3
>>> conn = sqlite3.connect('somedatabase.db')

之后就能获得连接的游标:

>>> curs = conn.cursor()

这个游标可以用来执行SQL查询。完成查询并且做出某些更改后确保已经进行了提交,这样才可以将这些修改真正地保存到文件中:

>>> conn.commit()

可以(而且是应该)在每次修改数据库后都进行提交,而不是仅仅在准备关闭时才提交,准备关闭数据库时,使用close方法:

>>> conn.close()

数据库应用程序示例

创建和填充表

# importdata.py
import sqlite

def convert(value):
    if value.startswith('~'):
        return value.strip('~')
    if not value:
        value = '0'
    return float(value)

conn = sqlite.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
)
''')

field_count = 10
markers = ', '.join(['%s']*field_count)
query = 'INSERT INTO food VALUES (?,?,?,?,?,?,?,?,?,?)' 

for line in open('ADD_FOOD.txt'):
    fields = line.split('^')
    vals = [convert(f) for f in fields[:field_count]]
    curs.execute(query, vals)

conn.commit()
conn.close()

搜索和处理结果

使用数据库——创建连接并且获得该连接的游标。使用execute方法执行SQL查询,用fetchall等方法提取结果。

# food_query.py
import sqlite, sys

conn = sqlite.connect('food.db')
curs = conn.cursor()

query = 'SELECT * FROM food WHERE %s' % 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 '%s: %s' % pair
    print

执行下面命令

$ python food_query.py "kcal <= 100 AND fiber >= 10 ORDER BY sugar"

小结

  • Python数据库编程接口(DB API)
  • 连接
  • 游标
  • 类型和特殊值
  • SQLite

推荐阅读更多精彩内容