sqlite3 遵循Python PDB-API 2.0 接口规范的SQLite库(2)

这是第二部分,也是最后一部分,关于SQLite3, -:)

13.13.3 Cursor 对象

一个cursor实例拥有如下的属性与方法:

l       execute( sql, [parameters])

执行一个SQL语句。SQL语句可以是参数化的(用占位符来代替具体的字面值)。Sqlite3支持两种类型的占位符:问号与命名。

下面的例子展示了如果使用问号:

import sqlite3

 

con = sqlite3.connect("mydb")

 

cur = con.cursor()

 

who = "Yeltsin"

age = 72

 

cur.execute("select name_last, age from people where name_last=? and age=?", (who, age))

print cur.fetchone()

 

下面的例子展示了如何使用命名:

import sqlite3

 

con = sqlite3.connect("mydb")

 

cur = con.cursor()

 

who = "Yeltsin"

age = 72

 

cur.execute("select name_last, age from people where name_last=:who and age=:age",

    {"who": who, "age": age})

print cur.fetchone()

方法execute()只能执行一条单独的SQL语句。如果你想要执行超过一条语句,将会引发一个warning。可以使用executescript()方法来在一次调用中执行多条SQL语句。

 

l       executemany( sql, seq_of_parameters)

使用seq_of_parameters中的值来多次调用SQL语句,seq_of_parameters可以是序列或映射。Sqlite3模块也支持会用迭代器生成参数来代替使用序列。

import sqlite3

 

class IterChars:

    def __init__(self):

        self.count = ord('a')

 

    def __iter__(self):

        return self

 

    def next(self):

        if self.count > ord('z'):

            raise StopIteration

        self.count += 1

        return (chr(self.count - 1),) # this is a 1-tuple

 

con = sqlite3.connect(":memory:")

cur = con.cursor()

cur.execute("create table characters(c)")

 

theIter = IterChars()

cur.executemany("insert into characters(c) values (?)", theIter)

 

cur.execute("select c from characters")

print cur.fetchall()

下面是一个使用迭代生成器的例子:

import sqlite3

 

def char_generator():

    import string

    for c in string.letters[:26]:

        yield (c,)

 

con = sqlite3.connect(":memory:")

cur = con.cursor()

cur.execute("create table characters(c)")

 

cur.executemany("insert into characters(c) values (?)", char_generator())

 

cur.execute("select c from characters")

print cur.fetchall()

 

l       executescript( sql_script)

这是一个非标准的可以在一次调用方便地执行多句SQL语句的方法。它首先发出一个COMMIT语句,之后执行SQL语句。

参数sql_script可以是一个bytestringUnicode编码的字符串。

示例如下:

 

import sqlite3

 

con = sqlite3.connect(":memory:")

cur = con.cursor()

cur.executescript("""

    create table person(

        firstname,

        lastname,

        age

    );

 

    create table book(

        title,

        author,

        published

    );

 

    insert into book(title, author, published)

    values (

        'Dirk Gently''s Holistic Detective Agency',

        'Douglas Adams',

        1987

    );

    """)

 

l       rowcount

虽然sqlite3模块中的cursor类实现了这个属性,但是数据库引擎自己对于“行数”统计的能力还是要强得多。

对于SELECT语句,rowcount总是为None,因为我们在所有行被取回前不能确定总的行数。

对于DELETE语句,当你在DELETE FROM 语句中没有使用任何条件的话,rowcount0

对于executemany语句,所有进行修改的行数都会被总计到rowcount中。

作为Python DB API规范的要求,在没有executeXX()方法被执行的情况下,或者在最近的一次操作中不能确定行数,则rowcount属性值将会是-1

 

 

13.13.4 SQLitePython类型

13.13.4.1 简介

SQLite只支持以下的内建类型:NULL, INTEGER, REAL, TEXT, BLOB.

因此,以下的Python类型可以毫无问题地传入SQLite

Python type             SQLite type

None                   NULL

int                     INTEGER

long                   INTEGER

float                    REAL

str (UTF8-encoded)        TEXT

unicode                 TEXT

buffer                   BLOB

 

下表说明了默认情况下SQLite类型如何被转换为Python类型:

SQLite type              Python type

NULL                   None

INTEGER                int or long, depending on size

REAL                   float

TEXT                   depends on text_factory, unicode by default

BLOB                   buffer

 

Sqlite3的类型系统可以有两种扩展方法:你可以通过对象适配器来将Python对象转换并存储到Sqlite数据库中,可以通过转换器将SQLite类型转换为Python对象。

 

13.13.4.2 使用适配器将其它Pyton类型转换到SQLite数据库中

象前面所说,SQLite本身只支持很少的类型。要在SQLite程序中使用其它的Python类型,你必须要将它们适配成为一种SQLite支持的数据类型:NoneType, int, long, float, str, unicode, buffer

Sqlite3模块使用Python对象适配器,就象在PEP246中所述的一样。所使用的协议为PrepareProtocol

有两种方法可以将一个定制Python类型适配成为SQLite支持的类型。

 

13.13.4.2.1 让你的对象具有自我适配能力

对于你自己定义的类,这是个比较好的办法,让我们假设你有一个类:

class Point(object):

    def __init__(self, x, y):

        self.x, self.y = x, y

现在你想将point信息存储在一个SQLite列中。首先,你要选择一个SQLite支持的类型来表示这个point对象。我们可以使用str类型,并坐标XY之间加入一个分号。然后,你需要在类中定义一个方法 __conform__(self, protocol),用来返回转换后的值。记住参数protocol要使用PrepareProtocol

import sqlite3

 

class Point(object):

    def __init__(self, x, y):

        self.x, self.y = x, y

 

    def __conform__(self, protocol):

        if protocol is sqlite3.PrepareProtocol:

            return "%f;%f" % (self.x, self.y)

 

con = sqlite3.connect(":memory:")

cur = con.cursor()

 

p = Point(4.0, -3.2)

cur.execute("select ?", (p,))

print cur.fetchone()[0]

 

13.13.4.2.2 注册一个适配器callable

另外一种可能是创建一个函数来将类型转换成表示它的字符串,并通过register_adapter来注册它。

注意:被适配的类型/类必须是一个新式样的class,就是说object类必须是它的基类之一。

import sqlite3

 

class Point(object):

    def __init__(self, x, y):

        self.x, self.y = x, y

 

def adapt_point(point):

    return "%f;%f" % (point.x, point.y)

 

sqlite3.register_adapter(Point, adapt_point)

 

con = sqlite3.connect(":memory:")

cur = con.cursor()

 

p = Point(4.0, -3.2)

cur.execute("select ?", (p,))

print cur.fetchone()[0]

sqlite3模块有两个针对Python内建类型datetime.datedatetime.datetime的默认适配器。现在假设我们想要存储datetime.datetime对象。

import sqlite3

import datetime, time

 

def adapt_datetime(ts):

    return time.mktime(ts.timetuple())

 

sqlite3.register_adapter(datetime.datetime, adapt_datetime)

 

con = sqlite3.connect(":memory:")

cur = con.cursor()

 

now = datetime.datetime.now()

cur.execute("select ?", (now,))

print cur.fetchone()[0]

 

13.13.4.3 SQLite值转换为Python定制类型

通过编写一个适配器可以让你将Python类型送入SQLite。但是要想让它发挥作用,我们还得完成从SQLite转换到Python的过程。

让我们回到Point 类。我们在SQLite中用分号分隔的格式存储了XY坐标信息。

首先,我们将定义一个转换函数,接收一个字符串作为参数,并从中构建一个Point对象。

注意:转换器函数总是用一个字符串参数来调用,而不管当初你送入SQLite的类型。

注意:转换器的名字是大小写敏感的。

    def convert_point(s):

        x, y = map(float, s.split(";"))

        return Point(x, y)

现在你要让sqlite3模块知道数据库中的那列数据是一个Point。有两种方法来实现:

l       通过声明类型隐含地表示

l       通过列名字明确地表示

两种方法都由模块常量来描述,还记得在13.13.1部分,常量PARSE_DECLTYPESPARSE_COLNAMES

下面的例子展示了这两种方法:

import sqlite3

 

class Point(object):

    def __init__(self, x, y):

        self.x, self.y = x, y

 

    def __repr__(self):

        return "(%f;%f)" % (self.x, self.y)

 

def adapt_point(point):

    return "%f;%f" % (point.x, point.y)

 

def convert_point(s):

    x, y = map(float, s.split(";"))

    return Point(x, y)

 

# Register the adapter

sqlite3.register_adapter(Point, adapt_point)

 

# Register the converter

sqlite3.register_converter("point", convert_point)

 

p = Point(4.0, -3.2)

 

#########################

# 1) 使用声明类型

con = sqlite3.connect(":memory:", detect_types=sqlite3.PARSE_DECLTYPES)

cur = con.cursor()

cur.execute("create table test(p point)")

 

cur.execute("insert into test(p) values (?)", (p,))

cur.execute("select p from test")

print "with declared types:", cur.fetchone()[0]

cur.close()

con.close()

 

#######################

# 1) 使用列名字

con = sqlite3.connect(":memory:", detect_types=sqlite3.PARSE_COLNAMES)

cur = con.cursor()

cur.execute("create table test(p)")

 

cur.execute("insert into test(p) values (?)", (p,))

cur.execute('select p as "p [point]" from test')

print "with column names:", cur.fetchone()[0]

cur.close()

con.close()

 

13.13.4.4 默认适配器与转换器

datatime模块中有针对datedatetime的默认适配器。它们将会被按ISO dateISO timestamps格式被传入到SQLite中。

注册好的默认转换器为datetime.date类型使用名字date,为类型datetime.datetime使用名字timestamp

这样,大部分情况下,你可以在Python中使用datetimestamps而不需要任何额外的处理。同时,适配器使用的格式也与正在试验中的SQLite date/time函数保持兼容。

以下是示例:

import sqlite3

import datetime

 

con = sqlite3.connect(":memory:", detect_types=sqlite3.PARSE_DECLTYPES | sqlite3.PARSE_COLNAMES )

cur = con.cursor()

cur.execute("create table test(d date, ts timestamp)")

 

today = datetime.date.today()

now = datetime.datetime.now()

 

cur.execute("insert into test(d, ts) values (?, ?)", (today, now))

cur.execute("select d, ts from test")

row = cur.fetchone()

print today, "=>", row[0], type(row[0])

print now, "=>", row[1], type(row[1])

 

cur.execute('select current_date as "d [date]", current_timestamp as "ts [timestamp]"')

row = cur.fetchone()

print "current_date", row[0], type(row[0])

print "current_timestamp", row[1], type(row[1])

 

13.13.5 控制事务

默认情况,sqlite3模块在数据修改语句(DML,如INSERTUPDATE DELETE REPLACE)开始执行前隐含地打开一个事务,并在开始一个非数据修改语句(任何非SELECT INSERT UPDATE DELETE REPLACE的语句)前确认事务。

所以若你在一个事务内,并且发出一个像CREATE TABLEVACUUMPRAGMA这样的命令,sqlite3将会在执行它们之前隐含地结束事务。有两个理由要这样做,第一个是一些这样的命令不能在事务中处理,另一个是pysqlite必须要对事务状态保持跟踪。

通过connect调用时的isolation_level,或者connection对象的isolation_level属性,我们都可以控制pysqlite隐含使用那种类型的”BEGIN”语句(或根本不执行此类语句)。

若你想使用autocommit模式,将isolation_level设置为None

要不然保持isolation_level的默认值,这将导致一个清楚的”BEGIN”语句,或者设成SQLite支持的值之一:DEFERRED, IMMEDIATE or EXCLUSIVE

因为sqlite3模块需要对事务状态保持跟踪,你还不应该在SQL中使用OR ROLLBACKON CONFLICT ROLLBACK语句,而要捕捉IntegrityError错误,再由你自己调用connection的回滚方法。

 

13.13.6 高效使用pysqlite

13.13.6.1 使用快捷方法

使用connection对象的非标准的executeexecutemany,及executescript方法,可以写出更加简洁的代码,因为不再需要明确地创建Cursor对象。Cursor对象会被隐含地创建,并由这些方法执行完后返回。我们可以只用一次调用就可以执行一句SELECT语句,并直接迭代处理结果集。

import sqlite3

 

persons = [

    ("Hugo", "Boss"),

    ("Calvin", "Klein")

    ]

 

con = sqlite3.connect(":memory:")

 

# Create the table

con.execute("create table person(firstname, lastname)")

 

# Fill the table

con.executemany("insert into person(firstname, lastname) values (?, ?)", persons)

 

# Print the table contents

for row in con.execute("select firstname, lastname from person"):

    print row

 

# Using a dummy WHERE clause to not let SQLite take the shortcut table deletes.

print "I just deleted", con.execute("delete from person where 1=1").rowcount, "rows"

13.13.6.2 使用列名而不是列索引来访问列数据

Sqlite3模块一个有用的功能是内建的sqlite3.Row类,它被设计作为一个row_factory

用这个类封闭的row可以通过列索引(像tuple)或列名(大小写敏感)来访问。

import sqlite3

 

con = sqlite3.connect("mydb")

con.row_factory = sqlite3.Row

 

cur = con.cursor()

cur.execute("select name_last, age from people")

for row in cur:

    assert row[0] == row["name_last"]

    assert row["name_last"] == row["nAmE_lAsT"]

    assert row[1] == row["age"]

    assert row[1] == row["AgE"]

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值