11.13. sqlite3 — SQLite 数据库的 DB-API 2.0 接口 — Python 文档
11.13. sqlite3 — SQLite 数据库的 DB-API 2.0 接口
2.5 版中的新功能。
SQLite 是一个 C 库,它提供了一个轻量级的基于磁盘的数据库,不需要单独的服务器进程,并允许使用 SQL 查询语言的非标准变体访问数据库。 某些应用程序可以使用 SQLite 进行内部数据存储。 还可以使用 SQLite 对应用程序进行原型设计,然后将代码移植到更大的数据库,例如 PostgreSQL 或 Oracle。
sqlite3 模块由 Gerhard Häring 编写。 它提供了符合 PEP 249 描述的 DB-API 2.0 规范的 SQL 接口。
要使用该模块,您必须首先创建一个表示数据库的 Connection 对象。 这里的数据将存储在 example.db
文件中:
import sqlite3
conn = sqlite3.connect('example.db')
您还可以提供特殊名称 :memory:
以在 RAM 中创建数据库。
一旦你有了一个 Connection,你就可以创建一个 Cursor 对象并调用它的 execute() 方法来执行 SQL 命令:
c = conn.cursor()
# Create table
c.execute('''CREATE TABLE stocks
(date text, trans text, symbol text, qty real, price real)''')
# Insert a row of data
c.execute("INSERT INTO stocks VALUES ('2006-01-05','BUY','RHAT',100,35.14)")
# Save (commit) the changes
conn.commit()
# We can also close the connection if we are done with it.
# Just be sure any changes have been committed or they will be lost.
conn.close()
您保存的数据是持久的,可在后续会话中使用:
import sqlite3
conn = sqlite3.connect('example.db')
c = conn.cursor()
通常,您的 SQL 操作需要使用 Python 变量中的值。 你不应该使用 Python 的字符串操作来组合你的查询,因为这样做是不安全的; 它使您的程序容易受到 SQL 注入攻击(请参阅 https://xkcd.com/327/ 有关可能出错的幽默示例)。
相反,使用 DB-API 的参数替换。 将 ?
作为占位符放在要使用值的任何位置,然后提供一个值元组作为光标的 execute() 方法的第二个参数。 (其他数据库模块可能使用不同的占位符,例如 %s
或 :1
。)例如:
# Never do this -- insecure!
symbol = 'RHAT'
c.execute("SELECT * FROM stocks WHERE symbol = '%s'" % symbol)
# Do this instead
t = ('RHAT',)
c.execute('SELECT * FROM stocks WHERE symbol=?', t)
print c.fetchone()
# Larger example that inserts many records at a time
purchases = [('2006-03-28', 'BUY', 'IBM', 1000, 45.00),
('2006-04-05', 'BUY', 'MSFT', 1000, 72.00),
('2006-04-06', 'SELL', 'IBM', 500, 53.00),
]
c.executemany('INSERT INTO stocks VALUES (?,?,?,?,?)', purchases)
要在执行 SELECT 语句后检索数据,您可以将游标视为 迭代器 ,调用游标的 fetchone() 方法检索单个匹配行,或调用 fetchall() 获取匹配行的列表。
此示例使用迭代器形式:
>>> for row in c.execute('SELECT * FROM stocks ORDER BY price'):
print row
(u'2006-01-05', u'BUY', u'RHAT', 100, 35.14)
(u'2006-03-28', u'BUY', u'IBM', 1000, 45.0)
(u'2006-04-06', u'SELL', u'IBM', 500, 53.0)
(u'2006-04-05', u'BUY', u'MSFT', 1000, 72.0)
也可以看看
- https://github.com/ghaering/pysqlite
- pysqlite 网页 – sqlite3 是在外部开发的,名称为“pysqlite”。
- https://www.sqlite.org
- SQLite 网页; 该文档描述了支持的 SQL 方言的语法和可用数据类型。
- http://www.w3schools.com/sql/
- 学习 SQL 语法的教程、参考和示例。
- PEP 249 - 数据库 API 规范 2.0
- PEP 由 Marc-André Lemburg 编写。
11.13.1. 模块函数和常量
- sqlite3.version
- 此模块的版本号,作为字符串。 这不是 SQLite 库的版本。
- sqlite3.version_info
- 此模块的版本号,作为整数元组。 这不是 SQLite 库的版本。
- sqlite3.sqlite_version
- 运行时 SQLite 库的版本号,作为字符串。
- sqlite3.sqlite_version_info
- 运行时 SQLite 库的版本号,作为整数元组。
- sqlite3.PARSE_DECLTYPES
此常量旨在与 connect() 函数的 detect_types 参数一起使用。
设置它会使 sqlite3 模块解析它返回的每一列的声明类型。 它将解析出声明类型的第一个单词,i。 e. 对于“integer primary key”,它会解析出“integer”,或者对于“number(10)”,它将解析出“number”。 然后对于该列,它将查看转换器字典并使用为该类型注册的转换器函数。
- sqlite3.PARSE_COLNAMES
此常量旨在与 connect() 函数的 detect_types 参数一起使用。
设置它会使 SQLite 接口解析它返回的每一列的列名。 它会在那里寻找一个形成 [mytype] 的字符串,然后确定 'mytype' 是列的类型。 它将尝试在转换器字典中找到“mytype”条目,然后使用在那里找到的转换器函数返回值。 在 Cursor.description 中找到的列名只是列名的第一个单词,即。 e. 如果您在 SQL 中使用
'as "x [datetime]"'
之类的内容,那么我们将解析所有内容,直到列名的第一个空格:列名将只是“x”。
- sqlite3.connect(database[, timeout, detect_types, isolation_level, check_same_thread, factory, cached_statements])
打开与 SQLite 数据库文件 数据库 的连接。 您可以使用
":memory:"
打开到驻留在 RAM 中而不是磁盘上的数据库的数据库连接。当一个数据库被多个连接访问,并且其中一个进程修改了该数据库时,SQLite 数据库将被锁定,直到该事务被提交。 timeout 参数指定连接应该等待锁定消失的时间,直到引发异常。 timeout 参数的默认值为 5.0(五秒)。
对于 isolation_level 参数,请参见 Connection 对象的 Connection.isolation_level 属性。
SQLite 本身只支持 TEXT、INTEGER、REAL、BLOB 和 NULL 类型。 如果您想使用其他类型,您必须自己添加对它们的支持。 detect_types 参数和使用模块级 register_converter() 函数注册的自定义 converters 可让您轻松做到这一点。
detect_types 默认为 0 (i. e. off,无类型检测),您可以将其设置为 PARSE_DECLTYPES 和 PARSE_COLNAMES 的任意组合来打开类型检测。
默认情况下,sqlite3 模块使用其 Connection 类进行连接调用。 但是,您可以将 Connection 类设为子类,并通过为 factory 参数提供您的类来使 connect() 使用您的类。
有关详细信息,请参阅本手册的 SQLite 和 Python 类型 部分。
sqlite3 模块内部使用语句缓存来避免 SQL 解析开销。 如果要显式设置为连接缓存的语句数,可以设置 cached_statements 参数。 当前实现的默认值是缓存 100 条语句。
- sqlite3.register_converter(typename, callable)
- 注册一个可调用对象,将数据库中的字节串转换为自定义 Python 类型。 将为 typename 类型的所有数据库值调用可调用对象。 赋予 connect() 函数的参数 detect_types 以了解类型检测的工作原理。 请注意, typename 和查询中的类型名称以不区分大小写的方式匹配。
- sqlite3.register_adapter(type, callable)
- 注册一个可调用对象以将自定义 Python 类型 type 转换为 SQLite 支持的类型之一。 callable callable 接受 Python 值作为单个参数,并且必须返回以下类型的值:int、long、float、str(UTF-8 编码)、unicode 或缓冲区。
- sqlite3.complete_statement(sql)
如果字符串 sql 包含一个或多个以分号结尾的完整 SQL 语句,则返回 True。 它不验证 SQL 在语法上是否正确,只验证没有未闭合的字符串文字并且语句以分号终止。
这可用于为 SQLite 构建 shell,如下例所示:
# A minimal SQLite shell for experiments import sqlite3 con = sqlite3.connect(":memory:") con.isolation_level = None cur = con.cursor() buffer = "" print "Enter your SQL commands to execute in sqlite3." print "Enter a blank line to exit." while True: line = raw_input() if line == "": break buffer += line if sqlite3.complete_statement(buffer): try: buffer = buffer.strip() cur.execute(buffer) if buffer.lstrip().upper().startswith("SELECT"): print cur.fetchall() except sqlite3.Error as e: print "An error occurred:", e.args[0] buffer = "" con.close()
- sqlite3.enable_callback_tracebacks(flag)
- 默认情况下,您不会在用户定义的函数、聚合、转换器、授权方回调等中获得任何回溯。 如果要调试它们,可以将 flag 设置为
True
来调用此函数。 之后,您将从sys.stderr
上的回调中获得回溯。 使用 False 再次禁用该功能。
11.13.2. 连接对象
- class sqlite3.Connection
SQLite 数据库连接具有以下属性和方法:
- isolation_level
获取或设置当前隔离级别。 None 用于自动提交模式或“DEFERRED”、“IMMEDIATE”或“EXCLUSIVE”之一。 有关更详细的说明,请参阅 控制事务 部分。
- cursor(factory=Cursor)
游标方法接受单个可选参数 factory。 如果提供,这必须是可调用的,返回 Cursor 或其子类的实例。
- commit()
此方法提交当前事务。 如果不调用此方法,则自上次调用
commit()
以来所做的任何事情都不会从其他数据库连接中看到。 如果你想知道为什么你看不到你写入数据库的数据,请检查你没有忘记调用这个方法。
- rollback()
此方法回滚自上次调用 commit() 以来对数据库的任何更改。
- execute(sql[, parameters])
这是一个非标准的快捷方式,它通过调用游标方法创建一个中间游标对象,然后使用给定的参数调用游标的 execute 方法。
- executemany(sql[, parameters])
这是一个非标准的快捷方式,它通过调用游标方法创建一个中间游标对象,然后使用给定的参数调用游标的 executemany 方法。
- executescript(sql_script)
这是一个非标准的快捷方式,它通过调用游标方法创建一个中间游标对象,然后使用给定的参数调用游标的 executescript 方法。
- create_function(name, num_params, func)
创建一个用户定义的函数,您以后可以在函数名 name 下的 SQL 语句中使用该函数。 num_params 是函数接受的参数个数,func 是一个 Python 可调用对象,作为 SQL 函数调用。
该函数可以返回 SQLite 支持的任何类型:unicode、str、int、long、float、buffer 和
None
。示例:
import sqlite3 import md5 def md5sum(t): return md5.md5(t).hexdigest() con = sqlite3.connect(":memory:") con.create_function("md5", 1, md5sum) cur = con.cursor() cur.execute("select md5(?)", ("foo",)) print cur.fetchone()[0]
- create_aggregate(name, num_params, aggregate_class)
创建用户定义的聚合函数。
聚合类必须实现一个
step
方法,该方法接受参数数量 num_params,以及一个finalize
方法,该方法将返回聚合的最终结果。finalize
方法可以返回 SQLite 支持的任何类型:unicode、str、int、long、float、buffer 和None
。示例:
import sqlite3 class MySum: def __init__(self): self.count = 0 def step(self, value): self.count += value def finalize(self): return self.count con = sqlite3.connect(":memory:") con.create_aggregate("mysum", 1, MySum) cur = con.cursor() cur.execute("create table test(i)") cur.execute("insert into test(i) values (1)") cur.execute("insert into test(i) values (2)") cur.execute("select mysum(i) from test") print cur.fetchone()[0]
- create_collation(name, callable)
创建具有指定 name 和 callable 的排序规则。 callable 将传递两个字符串参数。 如果第一个排序低于第二个,则返回 -1,如果它们相等则返回 0,如果第一个排序高于第二个则返回 1。 请注意,这控制排序(SQL 中的 ORDER BY),因此您的比较不会影响其他 SQL 操作。
请注意,可调用对象将其参数作为 Python 字节串获取,通常以 UTF-8 编码。
以下示例显示了一个以“错误方式”排序的自定义排序规则:
import sqlite3 def collate_reverse(string1, string2): return -cmp(string1, string2) con = sqlite3.connect(":memory:") con.create_collation("reverse", collate_reverse) cur = con.cursor() cur.execute("create table test(x)") cur.executemany("insert into test(x) values (?)", [("a",), ("b",)]) cur.execute("select x from test order by x collate reverse") for row in cur: print row con.close()
要删除排序规则,请使用
None
调用create_collation
作为可调用:con.create_collation("reverse", None)
- interrupt()
您可以从不同的线程调用此方法以中止可能在连接上执行的任何查询。 然后查询将中止,调用者将收到异常。
- set_authorizer(authorizer_callback)
该例程注册一个回调。 每次尝试访问数据库中表的列时都会调用回调。 如果允许访问,回调应返回
SQLITE_OK
,如果整个 SQL 语句应因错误而中止,则应返回SQLITE_DENY
,如果列应被视为 NULL 值,则应返回SQLITE_IGNORE
。 这些常量在 sqlite3 模块中可用。回调的第一个参数表示要授权的操作类型。 第二个和第三个参数将是参数或 None 取决于第一个参数。 如果适用,第四个参数是数据库的名称(“main”、“temp”等)。 第 5 个参数是负责访问尝试的最内部触发器或视图的名称,如果此访问尝试直接来自输入 SQL 代码,则为 None。
请查阅 SQLite 文档,了解第一个参数的可能值以及第二个和第三个参数的含义(取决于第一个参数)。 sqlite3 模块中提供了所有必需的常量。
- set_progress_handler(handler, n)
该例程注册一个回调。 为 SQLite 虚拟机的每个 n 条指令调用回调。 如果您想在长时间运行的操作期间从 SQLite 调用,这很有用,例如更新 GUI。
如果要清除任何以前安装的进度处理程序,请使用 None 调用 handler 的方法。
2.6 版中的新功能。
- enable_load_extension(enabled)
此例程允许/禁止 SQLite 引擎从共享库加载 SQLite 扩展。 SQLite 扩展可以定义新函数、聚合或全新的虚拟表实现。 一个众所周知的扩展是随 SQLite 分发的全文搜索扩展。
默认情况下禁用可加载扩展。 参见 1。
2.7 版中的新功能。
import sqlite3 con = sqlite3.connect(":memory:") # enable extension loading con.enable_load_extension(True) # Load the fulltext search extension con.execute("select load_extension('./fts3.so')") # alternatively you can load the extension using an API call: # con.load_extension("./fts3.so") # disable extension loading again con.enable_load_extension(False) # example from SQLite wiki con.execute("create virtual table recipe using fts3(name, ingredients)") con.executescript(""" insert into recipe (name, ingredients) values ('broccoli stew', 'broccoli peppers cheese tomatoes'); insert into recipe (name, ingredients) values ('pumpkin stew', 'pumpkin onions garlic celery'); insert into recipe (name, ingredients) values ('broccoli pie', 'broccoli cheese onions flour'); insert into recipe (name, ingredients) values ('pumpkin pie', 'pumpkin sugar flour butter'); """) for row in con.execute("select rowid, name, ingredients from recipe where name match 'pie'"): print row
- load_extension(path)
此例程从共享库加载 SQLite 扩展。 在使用此例程之前,您必须使用 enable_load_extension() 启用扩展加载。
默认情况下禁用可加载扩展。 参见 1。
2.7 版中的新功能。
- row_factory
您可以将此属性更改为接受游标和原始行作为元组并返回实际结果行的可调用对象。 通过这种方式,您可以实现更高级的返回结果的方式,例如返回一个也可以按名称访问列的对象。
示例:
import sqlite3 def dict_factory(cursor, row): d = {} for idx, col in enumerate(cursor.description): d[col[0]] = row[idx] return d con = sqlite3.connect(":memory:") con.row_factory = dict_factory cur = con.cursor() cur.execute("select 1 as a") print cur.fetchone()["a"]
如果返回元组还不够,并且您希望基于名称访问列,则应考虑将 row_factory 设置为高度优化的 sqlite3.Row 类型。 Row 提供对列的基于索引和不区分大小写的基于名称的访问,几乎没有内存开销。 它可能比您自己的基于字典的自定义方法甚至基于 db_row 的解决方案更好。
- text_factory
使用此属性,您可以控制为
TEXT
数据类型返回哪些对象。 默认情况下,此属性设置为 unicode 并且 sqlite3 模块将返回TEXT
的 Unicode 对象。 如果您想返回字节串,可以将其设置为 str。出于效率原因,还有一种方法可以只为非 ASCII 数据返回 Unicode 对象,否则返回字节串。 要激活它,请将此属性设置为
sqlite3.OptimizedUnicode
。您还可以将其设置为任何其他接受单个字节串参数并返回结果对象的可调用对象。
请参阅以下示例代码以进行说明:
import sqlite3 con = sqlite3.connect(":memory:") cur = con.cursor() AUSTRIA = u"\xd6sterreich" # by default, rows are returned as Unicode cur.execute("select ?", (AUSTRIA,)) row = cur.fetchone() assert row[0] == AUSTRIA # but we can make sqlite3 always return bytestrings ... con.text_factory = str cur.execute("select ?", (AUSTRIA,)) row = cur.fetchone() assert type(row[0]) is str # the bytestrings will be encoded in UTF-8, unless you stored garbage in the # database ... assert row[0] == AUSTRIA.encode("utf-8") # we can also implement a custom text_factory ... # here we implement one that will ignore Unicode characters that cannot be # decoded from UTF-8 con.text_factory = lambda x: unicode(x, "utf-8", "ignore") cur.execute("select ?", ("this is latin1 and would normally create errors" + u"\xe4\xf6\xfc".encode("latin1"),)) row = cur.fetchone() assert type(row[0]) is unicode # sqlite3 offers a built-in optimized text_factory that will return bytestring # objects, if the data is in ASCII only, and otherwise return unicode objects con.text_factory = sqlite3.OptimizedUnicode cur.execute("select ?", (AUSTRIA,)) row = cur.fetchone() assert type(row[0]) is unicode cur.execute("select ?", ("Germany",)) row = cur.fetchone() assert type(row[0]) is str
- total_changes
返回自数据库连接打开以来已修改、插入或删除的数据库行总数。
- iterdump
返回一个迭代器以 SQL 文本格式转储数据库。 在保存内存数据库以供以后恢复时很有用。 此函数提供与 sqlite3 shell 中的 .dump 命令相同的功能。
2.6 版中的新功能。
示例:
# Convert file existing_db.db to SQL dump file dump.sql import sqlite3, os con = sqlite3.connect('existing_db.db') with open('dump.sql', 'w') as f: for line in con.iterdump(): f.write('%s\n' % line)
11.13.3. 光标对象
- class sqlite3.Cursor
Cursor 实例具有以下属性和方法。
- execute(sql[, parameters])
执行 SQL 语句。 SQL 语句可以被参数化(即。 e. 占位符而不是 SQL 文字)。 sqlite3模块支持两种占位符:问号(qmark风格)和命名占位符(命名风格)。
这是两种样式的示例:
import sqlite3 con = sqlite3.connect(":memory:") cur = con.cursor() cur.execute("create table people (name_last, age)") who = "Yeltsin" age = 72 # This is the qmark style: cur.execute("insert into people values (?, ?)", (who, age)) # And this is the named style: cur.execute("select * from people where name_last=:who and age=:age", {"who": who, "age": age}) print cur.fetchone()
execute() 只会执行一条 SQL 语句。 如果您尝试使用它执行多个语句,则会引发警告。 如果要一次调用执行多个 SQL 语句,请使用 executescript()。
- executemany(sql, seq_of_parameters)
针对在序列 sql 中找到的所有参数序列或映射执行 SQL 命令。 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 import string def char_generator(): for c in string.lowercase: 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()
- executescript(sql_script)
这是一次执行多个 SQL 语句的非标准便捷方法。 它首先发出
COMMIT
语句,然后执行它作为参数获取的 SQL 脚本。sql_script 可以是字节串或 Unicode 串。
示例:
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 ); """)
- fetchone()
获取查询结果集的下一行,返回单个序列,或者在没有更多数据可用时返回 None。
- fetchmany([size=cursor.arraysize])
获取查询结果的下一组行,返回一个列表。 当没有更多行可用时,将返回一个空列表。
每次调用要获取的行数由 size 参数指定。 如果没有给出,游标的数组大小决定了要获取的行数。 该方法应尝试获取由 size 参数指示的尽可能多的行。 如果由于指定的行数不可用而无法执行此操作,则可能会返回较少的行。
请注意,size 参数涉及性能注意事项。 为了获得最佳性能,通常最好使用 arraysize 属性。 如果使用 size 参数,那么最好让它从一个 fetchmany() 调用到下一个调用保持相同的值。
- fetchall()
获取查询结果的所有(剩余)行,返回一个列表。 请注意,游标的 arraysize 属性会影响此操作的性能。 当没有可用行时,返回一个空列表。
- rowcount
尽管 sqlite3 模块的 Cursor 类实现了该属性,但数据库引擎自身对确定“受影响的行”/“选定的行”的支持是古怪的。
对于 executemany() 语句,修改次数汇总为 rowcount。
根据 Python DB API 规范的要求,rowcount 属性“为 -1,以防在游标上未执行
executeXX()
或接口无法确定最后一次操作的行数”。 这包括SELECT
语句,因为在获取所有行之前我们无法确定查询生成的行数。对于 3.6.5 之前的 SQLite 版本,如果您在没有任何条件的情况下创建
DELETE FROM table
,则 rowcount 将设置为 0。
- lastrowid
此只读属性提供最后修改行的 rowid。 仅当您使用 execute() 方法发出
INSERT
语句时才设置它。 对于除INSERT
以外的操作或调用 executemany() 时,lastrowid 设置为 None。
- description
此只读属性提供最后一个查询的列名。 为了与 Python DB API 保持兼容,它为每列返回一个 7 元组,其中每个元组的最后六项是 None。
它也适用于没有任何匹配行的
SELECT
语句。
- connection
此只读属性提供 Cursor 对象使用的 SQLite 数据库 Connection。 通过调用 con.cursor() 创建的 Cursor 对象将具有引用 con 的 connection 属性:
>>> con = sqlite3.connect(":memory:") >>> cur = con.cursor() >>> cur.connection == con True
11.13.4. 行对象
- class sqlite3.Row
Row 实例用作 Connection 对象的高度优化的 row_factory。 它试图在其大部分功能中模仿元组。
它支持按列名和索引、迭代、表示、相等性测试和 len() 进行映射访问。
如果两个 Row 对象具有完全相同的列并且它们的成员相等,则它们比较相等。
在 2.6 版更改: 添加了迭代和相等性(哈希性)。
- keys()
此方法返回一个列名列表。 在查询之后,它是 Cursor.description 中每个元组的第一个成员。
2.6 版中的新功能。
假设我们按照上面给出的示例初始化一个表:
conn = sqlite3.connect(":memory:")
c = conn.cursor()
c.execute('''create table stocks
(date text, trans text, symbol text,
qty real, price real)''')
c.execute("""insert into stocks
values ('2006-01-05','BUY','RHAT',100,35.14)""")
conn.commit()
c.close()
现在我们将 Row 插入:
>>> conn.row_factory = sqlite3.Row
>>> c = conn.cursor()
>>> c.execute('select * from stocks')
<sqlite3.Cursor object at 0x7f4e7dd8fa80>
>>> r = c.fetchone()
>>> type(r)
<type 'sqlite3.Row'>
>>> r
(u'2006-01-05', u'BUY', u'RHAT', 100.0, 35.14)
>>> len(r)
5
>>> r[2]
u'RHAT'
>>> r.keys()
['date', 'trans', 'symbol', 'qty', 'price']
>>> r['qty']
100.0
>>> for member in r:
... print member
...
2006-01-05
BUY
RHAT
100.0
35.14
11.13.5. SQLite 和 Python 类型
11.13.5.1。 介绍
SQLite 本身支持以下类型:NULL
、INTEGER
、REAL
、TEXT
、BLOB
。
因此,以下 Python 类型可以毫无问题地发送到 SQLite:
蟒蛇型 | SQLite 类型 |
---|---|
None
|
NULL
|
int
|
INTEGER
|
long
|
INTEGER
|
float
|
REAL
|
str(UTF8 编码) | TEXT
|
unicode
|
TEXT
|
buffer
|
BLOB
|
这是默认情况下 SQLite 类型转换为 Python 类型的方式:
SQLite 类型 | 蟒蛇型 |
---|---|
NULL
|
None
|
INTEGER
|
int 或 long,取决于大小 |
REAL
|
float
|
TEXT
|
默认依赖于 text_factory, unicode |
BLOB
|
buffer
|
sqlite3模块的类型系统有两种扩展方式:可以通过对象适配在SQLite数据库中存储额外的Python类型,可以让sqlite3模块将SQLite类型转换为不同的 Python 类型通过转换器。
11.13.5.2. 使用适配器在 SQLite 数据库中存储额外的 Python 类型
如前所述,SQLite 本身只支持有限的一组类型。 要在 SQLite 中使用其他 Python 类型,您必须 使 它们适应 SQLite 的 sqlite3 模块支持的类型之一:NoneType、int、long、float、str、unicode、buffer 之一。
有两种方法可以使 sqlite3 模块使自定义 Python 类型适应受支持的类型之一。
11.13.5.2.1。 让你的对象适应自己
如果您自己编写类,这是一个很好的方法。 假设你有一个这样的类:
class Point(object):
def __init__(self, x, y):
self.x, self.y = x, y
现在您想将该点存储在单个 SQLite 列中。 首先,您必须首先选择一种受支持的类型来表示点。 让我们只使用 str 并使用分号分隔坐标。 然后你需要给你的类一个方法 __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]
11.13.5.2.2. 注册一个可调用的适配器
另一种可能性是创建一个将类型转换为字符串表示的函数,并使用 register_adapter() 注册该函数。
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.date 和 datetime.datetime 类型。 现在让我们假设我们想要存储 datetime.datetime 对象不是以 ISO 表示形式,而是作为 Unix 时间戳。
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]
11.13.5.3。 将 SQLite 值转换为自定义 Python 类型
编写适配器可让您将自定义 Python 类型发送到 SQLite。 但是为了让它真正有用,我们需要让 Python 到 SQLite 再到 Python 的往返工作。
输入转换器。
让我们回到 Point
类。 我们将通过分号分隔的 x 和 y 坐标存储为 SQLite 中的字符串。
首先,我们将定义一个转换器函数,它接受字符串作为参数并从中构造一个 Point
对象。
笔记
转换器函数 总是 使用字符串调用,无论您将值发送到 SQLite 的数据类型是什么。
def convert_point(s):
x, y = map(float, s.split(";"))
return Point(x, y)
现在你需要让 sqlite3 模块知道你从数据库中选择的实际上是一个点。 有两种方法可以做到这一点:
- 通过声明的类型隐式
- 显式通过列名
这两种方式都在 模块函数和常量 节中描述,在常量 PARSE_DECLTYPES 和 PARSE_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) Using declared types
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) Using column names
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()
11.13.5.4. 默认适配器和转换器
datetime 模块中有用于日期和日期时间类型的默认适配器。 它们将作为 ISO 日期/ISO 时间戳发送到 SQLite。
默认转换器在 datetime.date 的名称为“date”,datetime.datetime 的名称为“timestamp”。
这样,在大多数情况下,您可以使用 Python 中的日期/时间戳,而无需任何额外的调整。 适配器的格式也与实验性 SQLite 日期/时间函数兼容。
以下示例演示了这一点。
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])
如果存储在 SQLite 中的时间戳的小数部分超过 6 个数字,则时间戳转换器将其值截断为微秒精度。
11.13.6. 控制交易
默认情况下,sqlite3 模块在数据修改语言 (DML) 语句(即 INSERT
/UPDATE
/DELETE
/REPLACE
),并在非 DML、非查询语句(即。 e. 除 SELECT
或上述内容之外的任何其他内容)。
因此,如果您在事务中并发出类似 CREATE TABLE ...
、VACUUM
、PRAGMA
的命令,sqlite3 模块将在执行该命令之前隐式提交。 这样做有两个原因。 首先是其中一些命令在事务中不起作用。 另一个原因是 sqlite3 需要跟踪事务状态(如果事务处于活动状态与否)。
您可以通过 connect() 调用的 isolation_level 参数或通过 isolation_level
连接属性。
如果要自动提交模式,则将isolation_level
设置为None
。
否则将其保留为默认值,这将导致一个简单的“BEGIN”语句,或将其设置为 SQLite 支持的隔离级别之一:“DEFERRED”、“IMMEDIATE”或“EXCLUSIVE”。
11.13.7. 使用 sqlite3 有效率的
11.13.7.1。 使用快捷方式
使用 Connection 对象的非标准 execute()
、executemany()
和 executescript()
方法,您的代码可以写得更简洁,因为您不必创建(通常是多余的) Cursor 对象显式。 相反,Cursor 对象是隐式创建的,这些快捷方法返回光标对象。 这样,您可以执行 SELECT
语句并直接使用 Connection 对象上的单个调用对其进行迭代。
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
print "I just deleted", con.execute("delete from person").rowcount, "rows"
11.13.7.2. 按名称而不是按索引访问列
sqlite3 模块的一个有用功能是内置的 sqlite3.Row 类,旨在用作行工厂。
可以通过索引(如元组)和不区分大小写的名称访问用此类包装的行:
import sqlite3
con = sqlite3.connect(":memory:")
con.row_factory = sqlite3.Row
cur = con.cursor()
cur.execute("select 'John' as name, 42 as age")
for row in cur:
assert row[0] == row["name"]
assert row["name"] == row["nAmE"]
assert row[1] == row["age"]
assert row[1] == row["AgE"]
11.13.7.3。 使用连接作为上下文管理器
2.6 版中的新功能。
连接对象可用作自动提交或回滚事务的上下文管理器。 发生异常时,事务回滚; 否则,事务被提交:
import sqlite3
con = sqlite3.connect(":memory:")
con.execute("create table person (id integer primary key, firstname varchar unique)")
# Successful, con.commit() is called automatically afterwards
with con:
con.execute("insert into person(firstname) values (?)", ("Joe",))
# con.rollback() is called after the with block finishes with an exception, the
# exception is still raised and must be caught
try:
with con:
con.execute("insert into person(firstname) values (?)", ("Joe",))
except sqlite3.IntegrityError:
print "couldn't add Joe twice"
11.13.8. 常见问题
11.13.8.1。 多线程
较旧的 SQLite 版本在线程之间共享连接方面存在问题。 这就是 Python 模块不允许在线程之间共享连接和游标的原因。 如果您仍然尝试这样做,您将在运行时收到异常。
唯一的例外是调用 interrupt() 方法,只有从不同的线程调用才有意义。
脚注
- 1(1,2)
- 默认情况下,sqlite3 模块没有使用可加载扩展支持构建,因为某些平台(特别是 Mac OS X)具有编译时没有此功能的 SQLite 库。 要获得可加载扩展支持,您必须修改 setup.py 并删除设置 SQLITE_OMIT_LOAD_EXTENSION 的行。