sqlite3 --- SQLite 數據庫 DB-API 2.0 接口模塊?
源代碼: Lib/sqlite3/
SQLite 是一個C語言庫,它可以提供一種輕量級的基于磁盤的數據庫,這種數據庫不需要獨立的服務器進程,也允許需要使用一種非標準的 SQL 查詢語言來訪問它。一些應用程序可以使用 SQLite 作為內部數據存儲。可以用它來創建一個應用程序原型,然后再遷移到更大的數據庫,比如 PostgreSQL 或 Oracle。
sqlite3 模塊由 Gerhard H?ring 編寫。它提供了符合 DB-API 2.0 規范的接口,這個規范是 PEP 249。
要使用這個模塊,必須先創建一個 Connection 對象,它代表數據庫。下面例子中,數據將存儲在 example.db 文件中:
import sqlite3
conn = sqlite3.connect('example.db')
你也可以使用 :memory: 來創建一個內存中的數據庫
當有了 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 的參數替換。在你的 SQL 語句中,使用 ? 占位符來代替值,然后把對應的值組成的元組做為 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 語句后獲取數據,你可以把游標作為 iterator,然后調用它的 fetchone() 方法來獲取一條匹配的行,也可以調用 fetchall() 來得到包含多個匹配行的列表。
下面是一個使用迭代器形式的例子:
>>> for row in c.execute('SELECT * FROM stocks ORDER BY price'):
print(row)
('2006-01-05', 'BUY', 'RHAT', 100, 35.14)
('2006-03-28', 'BUY', 'IBM', 1000, 45.0)
('2006-04-06', 'SELL', 'IBM', 500, 53.0)
('2006-04-05', 'BUY', 'MSFT', 1000, 72.0)
參見
- https://github.com/ghaering/pysqlite
pysqlite的主頁 -- sqlite3 在外部使用 “pysqlite” 名字進行開發。
- https://www.sqlite.org
SQLite的主頁;它的文檔詳細描述了它所支持的 SQL 方言的語法和可用的數據類型。
- https://www.w3schools.com/sql/
學習 SQL 語法的教程、參考和例子。
- PEP 249 - DB-API 2.0 規范
Marc-André Lemburg 寫的 PEP。
模塊函數和常量?
-
sqlite3.version? 這個模塊的版本號,是一個字符串。不是 SQLite 庫的版本號。
-
sqlite3.version_info? 這個模塊的版本號,是一個由整數組成的元組。不是 SQLite 庫的版本號。
-
sqlite3.sqlite_version? 使用中的 SQLite 庫的版本號,是一個字符串。
-
sqlite3.sqlite_version_info? 使用中的 SQLite 庫的版本號,是一個整數組成的元組。
-
sqlite3.PARSE_DECLTYPES? 這個常量可以作為
connect()函數的 detect_types 參數。設置這個參數后,
sqlite3模塊將解析它返回的每一列申明的類型。它會申明的類型的第一個單詞,比如“integer primary key”,它會解析出“integer”,再比如“number(10)”,它會解析出“number”。然后,它會在轉換器字典里查找那個類型注冊的轉換器函數,并調用它。
-
sqlite3.PARSE_COLNAMES? 這個常量可以作為
connect()函數的 detect_types 參數。設置此參數可使得 SQLite 接口解析它所返回的每一列的列名。 它將在其中查找形式為 [mytype] 的字符串,然后將 'mytype' 確定為列的類型。 它將嘗試在轉換器字典中查找 'mytype' 條目,然后用找到的轉換器函數來返回值。 在
Cursor.description中找到的列名并不包括類型,舉例來說,如果你在你的 SQL 中使用了像'as "Expiration date [datetime]"'這樣的寫法,那么我們將解析出在第一個 then we will parse out everything until the first'['之前的所有內容并去除前導空格作為列名:即列名將為 "Expiration date"。
-
sqlite3.connect(database[, timeout, detect_types, isolation_level, check_same_thread, factory, cached_statements, uri])? 連接 SQLite 數據庫 database。默認返回
Connection對象,除非使用了自定義的 factory 參數。database 是準備打開的數據庫文件的路徑(絕對路徑或相對于當前目錄的相對路徑),它是 path-like object。你也可以用
":memory:"在內存中打開一個數據庫。當一個數據庫被多個連接訪問的時候,如果其中一個進程修改這個數據庫,在這個事務提交之前,這個 SQLite 數據庫將會被一直鎖定。timeout 參數指定了這個連接等待鎖釋放的超時時間,超時之后會引發一個異常。這個超時時間默認是 5.0(5秒)。
isolation_level 參數,請查看
Connection對象的isolation_level屬性。SQLite 原生只支持5種類型:TEXT,INTEGER,REAL,BLOB 和 NULL。如果你想用其它類型,你必須自己添加相應的支持。使用 detect_types 參數和模塊級別的
register_converter()函數注冊**轉換器** 可以簡單的實現。detect_types 默認為0(即關閉,沒有類型檢測)。你也可以組合
PARSE_DECLTYPES和PARSE_COLNAMES來開啟類型檢測。默認情況下,check_same_thread 為
True,只有當前的線程可以使用該連接。 如果設置為False,則多個線程可以共享返回的連接。 當多個線程使用同一個連接的時候,用戶應該把寫操作進行序列化,以避免數據損壞。默認情況下,當調用 connect 方法的時候,
sqlite3模塊使用了它的Connection類。當然,你也可以創建Connection類的子類,然后創建提供了 factory 參數的connect()方法。詳情請查閱當前手冊的 SQLite 與 Python 類型 部分。
sqlite3模塊在內部使用語句緩存來避免 SQL 解析開銷。 如果要顯式設置當前連接可以緩存的語句數,可以設置 cached_statements 參數。 當前實現的默認值是緩存100條語句。如果 uri 為真,則 database 被解釋為 URI。 它允許您指定選項。 例如,以只讀模式打開數據庫:
db = sqlite3.connect('file:path/to/database?mode=ro', uri=True)
有關此功能的更多信息,包括已知選項的列表,可以在 ` SQLite URI 文檔 <https://www.sqlite.org/uri.html>`_ 中找到。
在 3.4 版更改: 增加了 uri 參數。
在 3.7 版更改: database 現在可以是一個 path-like object 對象了,不僅僅是字符串。
-
sqlite3.register_converter(typename, callable)? 注冊一個回調對象 callable, 用來轉換數據庫中的字節串為自定的 Python 類型。所有類型為 typename 的數據庫的值在轉換時,都會調用這個回調對象。通過指定
connect()函數的 detect-types 參數來設置類型檢測的方式。注意,typename 與查詢語句中的類型名進行匹配時不區分大小寫。
-
sqlite3.register_adapter(type, callable)? 注冊一個回調對象 callable,用來轉換自定義Python類型為一個 SQLite 支持的類型。 這個回調對象 callable 僅接受一個 Python 值作為參數,而且必須返回以下某個類型的值:int,float,str 或 bytes。
-
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 = 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()
連接對象(Connection)?
-
class
sqlite3.Connection? SQLite 數據庫連接對象有如下的屬性和方法:
-
isolation_level? 獲取或設置當前默認的隔離級別。 表示自動提交模式的
None以及 "DEFERRED", "IMMEDIATE" 或 "EXCLUSIVE" 其中之一。 詳細描述請參閱 控制事務。
-
commit()? 這個方法提交當前事務。如果沒有調用這個方法,那么從上一次提交
commit()以來所有的變化在其他數據庫連接上都是不可見的。如果你往數據庫里寫了數據,但是又查詢不到,請檢查是否忘記了調用這個方法。
-
execute(sql[, parameters])? 這是一個非標準的快捷方法,它會調用
cursor()方法來創建一個游標對象,并使用給定的 parameters 參數來調用游標對象的execute()方法,最后返回這個游標對象。
-
executemany(sql[, parameters])? 這是一個非標準的快捷方法,它會調用
cursor()方法來創建一個游標對象,并使用給定的 parameters 參數來調用游標對象的executemany()方法,最后返回這個游標對象。
-
executescript(sql_script)? 這是一個非標準的快捷方法,它會調用
cursor()方法來創建一個游標對象,并使用給定的 sql_script 參數來調用游標對象的executescript()方法,最后返回這個游標對象。
-
create_function(name, num_params, func)? 創建一個可以在 SQL 語句中使用的自定義函數,其中參數 name 為 SQL 語句中使用的函數名,num_params 是這個函數接受的參數個數(如果 num_params 為 -1,那這個函數可以接受任意數量的參數),最后一個參數 func 是作為 SQL 函數調用的一個 Python 可調用對象。
此函數可返回任何 SQLite 所支持的類型: bytes, str, int, float 和
None。示例:
import sqlite3 import hashlib def md5sum(t): return hashlib.md5(t).hexdigest() con = sqlite3.connect(":memory:") con.create_function("md5", 1, md5sum) cur = con.cursor() cur.execute("select md5(?)", (b"foo",)) print(cur.fetchone()[0]) con.close()
-
create_aggregate(name, num_params, aggregate_class)? 創建一個自定義的聚合函數。
參數中 aggregate_class 類必須實現兩個方法:
step和finalize。step方法接受 num_params 個參數(如果 num_params 為 -1,那么這個函數可以接受任意數量的參數);finalize方法返回最終的聚合結果。finalize方法可以返回任何 SQLite 支持的類型:bytes,str,int,float 和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]) con.close()
-
create_collation(name, callable)? 使用 name 和 callable 創建排序規則。這個 callable 接受兩個字符串對象,如果第一個小于第二個則返回 -1, 如果兩個相等則返回 0,如果第一個大于第二個則返回 1。注意,這是用來控制排序的(SQL 中的 ORDER BY),所以它不會影響其它的 SQL 操作。
注意,這個 callable 可調用對象會把它的參數作為 Python 字節串,通常會以 UTF-8 編碼格式對它進行編碼。
以下示例顯示了使用“錯誤方式”進行排序的自定義排序規則:
import sqlite3 def collate_reverse(string1, string2): if string1 == string2: return 0 elif string1 < string2: return 1 else: return -1 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()
要移除一個排序規則,需要調用
create_collation并設置 callable 參數為None。con.create_collation("reverse", None)
-
interrupt()? 可以從不同的線程調用這個方法來終止所有查詢操作,這些查詢操作可能正在連接上執行。此方法調用之后, 查詢將會終止,而且查詢的調用者會獲得一個異常。
此方法注冊一個授權回調對象。每次在訪問數據庫中某個表的某一列的時候,這個回調對象將會被調用。如果要允許訪問,則返回
SQLITE_OK,如果要終止整個 SQL 語句,則返回SQLITE_DENY,如果這一列需要當做 NULL 值處理,則返回SQLITE_IGNORE。這些常量可以在sqlite3模塊中找到。回調的第一個參數表示要授權的操作類型。 第二個和第三個參數將是參數或
None,具體取決于第一個參數的值。 第 4 個參數是數據庫的名稱(“main”,“temp”等),如果需要的話。 第 5 個參數是負責訪問嘗試的最內層觸發器或視圖的名稱,或者如果此訪問嘗試直接來自輸入 SQL 代碼,則為None。請參閱 SQLite 文檔,了解第一個參數的可能值以及第二個和第三個參數的含義,具體取決于第一個參數。 所有必需的常量都可以在
sqlite3模塊中找到。
-
set_progress_handler(handler, n)? 此例程注冊回調。 對SQLite虛擬機的每個多指令調用回調。 如果要在長時間運行的操作期間從SQLite調用(例如更新用戶界面),這非常有用。
如果要清除以前安裝的任何進度處理程序,調用該方法時請將 handler 參數設置為
None。從處理函數返回非零值將終止當前正在執行的查詢并導致它引發
OperationalError異常。
-
set_trace_callback(trace_callback)? 為每個 SQLite 后端實際執行的 SQL 語句注冊要調用的 trace_callback。
傳遞給回調的唯一參數是正在執行的語句(作為字符串)。 回調的返回值將被忽略。 請注意,后端不僅運行傳遞給
Cursor.execute()方法的語句。 其他來源包括 Python 模塊的事務管理和當前數據庫中定義的觸發器的執行。將傳入的 trace_callback 設為
None將禁用跟蹤回調。3.3 新版功能.
-
enable_load_extension(enabled)? 此例程允許/禁止SQLite引擎從共享庫加載SQLite擴展。 SQLite擴展可以定義新功能,聚合或全新的虛擬表實現。 一個眾所周知的擴展是與SQLite一起分發的全文搜索擴展。
默認情況下禁用可加載擴展。 見 1.
3.2 新版功能.
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) con.close()
-
load_extension(path)? 此例程從共享庫加載SQLite擴展。 在使用此例程之前,必須使用
enable_load_extension()啟用擴展加載。默認情況下禁用可加載擴展。 見 1.
3.2 新版功能.
-
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"]) con.close()
如果返回一個元組是不夠的,并且你想要對列進行基于名稱的訪問,你應該考慮將
row_factory設置為高度優化的sqlite3.Row類型。Row提供基于索引和不區分大小寫的基于名稱的訪問,幾乎沒有內存開銷。 它可能比您自己的基于字典的自定義方法甚至基于 db_row 的解決方案更好。
-
text_factory? 使用此屬性可以控制為
TEXT數據類型返回的對象。 默認情況下,此屬性設置為str和sqlite3模塊將返回TEXT的 Unicode 對象。 如果要返回字節串,可以將其設置為bytes。您還可以將其設置為接受單個 bytestring 參數的任何其他可調用對象,并返回結果對象。
請參閱以下示例代碼以進行說明:
import sqlite3 con = sqlite3.connect(":memory:") cur = con.cursor() AUSTRIA = "\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 = bytes cur.execute("select ?", (AUSTRIA,)) row = cur.fetchone() assert type(row[0]) is bytes # 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 appends "foo" to all strings con.text_factory = lambda x: x.decode("utf-8") + "foo" cur.execute("select ?", ("bar",)) row = cur.fetchone() assert row[0] == "barfoo" con.close()
-
total_changes? 返回自打開數據庫連接以來已修改,插入或刪除的數據庫行的總數。
-
iterdump()? 返回以SQL文本格式轉儲數據庫的迭代器。 保存內存數據庫以便以后恢復時很有用。 此函數提供與 sqlite3 shell 中的 .dump 命令相同的功能。
示例:
# Convert file existing_db.db to SQL dump file dump.sql import sqlite3 con = sqlite3.connect('existing_db.db') with open('dump.sql', 'w') as f: for line in con.iterdump(): f.write('%s\n' % line) con.close()
-
backup(target, *, pages=0, progress=None, name="main", sleep=0.250)? 即使在 SQLite 數據庫被其他客戶端訪問時,或者同時由同一連接訪問,該方法也會對其進行備份。 該副本將寫入強制參數 target,該參數必須是另一個
Connection實例。默認情況下,或者當 pages 為
0或負整數時,整個數據庫將在一個步驟中復制;否則該方法一次循環復制 pages 規定數量的頁面。如果指定了 progress,則它必須為
None或一個將在每次迭代時附帶三個整數參數執行的可調用對象,這三個參數分別是前一次迭代的狀態 status,將要拷貝的剩余頁數 remaining 以及總頁數 total。name 參數指定將被拷貝的數據庫名稱:它必須是一個字符串,其內容為表示主數據庫的默認值
"main",表示臨時數據庫的"temp"或是在ATTACH DATABASE語句的AS關鍵字之后指定表示附加數據庫的名稱。sleep 參數指定在備份剩余頁的連續嘗試之間要休眠的秒數,可以指定為一個整數或一個浮點數值。
示例一,將現有數據庫復制到另一個數據庫中:
import sqlite3 def progress(status, remaining, total): print(f'Copied {total-remaining} of {total} pages...') con = sqlite3.connect('existing_db.db') bck = sqlite3.connect('backup.db') with bck: con.backup(bck, pages=1, progress=progress) bck.close() con.close()
示例二,將現有數據庫復制到臨時副本中:
import sqlite3 source = sqlite3.connect('existing_db.db') dest = sqlite3.connect(':memory:') source.backup(dest)
可用性:SQLite 3.6.11 或以上版本
3.7 新版功能.
-
Cursor 對象?
-
class
sqlite3.Cursor? Cursor游標實例具有以下屬性和方法。-
execute(sql[, parameters])? 執行SQL語句。 可以是參數化 SQL 語句(即,在 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()) con.close()
execute()將只執行一條單獨的 SQL 語句。 如果你嘗試用它執行超過一條語句,將會引發Warning。 如果你想要用一次調用執行多條 SQL 語句請使用executescript()。
-
executemany(sql, seq_of_parameters)? 基于在序列 seq_of_parameters 中找到的所有形參序列或映射執行一條 SQL 命令。
sqlite3模塊還允許使用 iterator 代替序列來產生形參。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()) con.close()
這是一個使用生成器 generator 的簡短示例:
import sqlite3 import string def char_generator(): for c in string.ascii_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()) con.close()
-
executescript(sql_script)? 這是一個非標準的便捷方法,可用于一次執行多條 SQL 語句。 它會首先執行一條
COMMIT語句,再執行以形參方式獲取的 SQL 腳本。sql_script 可以是一個
str類的實例。示例:
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 ); """) con.close()
-
fetchmany(size=cursor.arraysize)? 獲取下一個多行查詢結果集,返回一個列表。 當沒有更多可用行時將返回一個空列表。
每次調用獲取的行數由 size 形參指定。 如果沒有給出該形參,則由 cursor 的 arraysize 決定要獲取的行數。 此方法將基于 size 形參值嘗試獲取指定數量的行。 如果獲取不到指定的行數,則可能返回較少的行。
請注意 size 形參會涉及到性能方面的考慮。為了獲得優化的性能,通常最好是使用 arraysize 屬性。 如果使用 size 形參,則最好在從一個
fetchmany()調用到下一個調用之間保持相同的值。
-
fetchall()? 獲取一個查詢結果的所有(剩余)行,返回一個列表。 請注意 cursor 的 arraysize 屬性會影響此操作的執行效率。 當沒有可用行時將返回一個空列表。
-
close()? 立即關閉 cursor(而不是在當
__del__被調用的時候)。從這一時刻起該 cursor 將不再可用,如果再嘗試用該 cursor 執行任何操作將引發
ProgrammingError異常。
-
rowcount? 雖然
sqlite3模塊的Cursor類實現了此屬性,但數據庫引擎本身對于確定 "受影響行"/"已選擇行" 的支持并不完善。對于
executemany()語句,修改行數會被匯總至rowcount。根據 Python DB API 規格描述的要求,
rowcount屬性 "當未在 cursor 上執行executeXX()或者上一次操作的 rowcount 不是由接口確定時為 -1"。 這包括SELECT語句,因為我們無法確定一次查詢將產生的行計數,而要等獲取了所有行時才會知道。。在 SQLite 的 3.6.5 版之前,如果你執行
DELETE FROM table時不附帶任何條件,則rowcount將被設為 0。
-
lastrowid? 這個只讀屬性會提供最近修改行的 rowid。 它只在你使用
execute()方法執行INSERT或REPLACE語句時會被設置。 對于INSERT或REPLACE以外的操作或者當executemany()被調用時,lastrowid會被設為None。如果
INSERT或REPLACE語句操作失敗則將返回上一次成功操作的 rowid。在 3.6 版更改: 增加了
REPLACE語句的支持。
-
arraysize? 用于控制
fetchmany()返回行數的可讀取/寫入屬性。 該屬性的默認值為 1,表示每次調用將獲取單獨一行。
-
description? 這個只讀屬性將提供上一次查詢的列名稱。 為了與 Python DB API 保持兼容,它會為每個列返回一個 7 元組,每個元組的最后六個條目均為
None。對于沒有任何匹配行的
SELECT語句同樣會設置該屬性。
-
connection? 這個只讀屬性將提供
Cursor對象所使用的 SQLite 數據庫Connection。 通過調用con.cursor()創建的Cursor對象所包含的connection屬性將指向 con:>>> con = sqlite3.connect(":memory:") >>> cur = con.cursor() >>> cur.connection == con True
-
行對象*Row*?
-
class
sqlite3.Row? 一個
Row實例,該實例將作為用于Connection對象的高度優化的row_factory。 它的大部分行為都會模仿元組的特性。它支持使用列名稱的映射訪問以及索引、迭代、文本表示、相等檢測和
len()等操作。如果兩個
Row對象具有完全相同的列并且其成員均相等,則它們的比較結果為相等。-
keys()? 此方法會在一次查詢之后立即返回一個列名稱的列表,它是
Cursor.description中每個元組的第一個成員。
在 3.5 版更改: 添加了對切片操作的支持。
-
讓我們假設我們如上面的例子所示初始化一個表:
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)
<class 'sqlite3.Row'>
>>> tuple(r)
('2006-01-05', 'BUY', 'RHAT', 100.0, 35.14)
>>> len(r)
5
>>> r[2]
'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
異常?
-
exception
sqlite3.DatabaseError? 針對數據庫相關錯誤引發的異常。
-
exception
sqlite3.IntegrityError? 當數據庫的關系一致性受到影響時引發的異常。 例如外鍵檢查失敗等。 它是
DatabaseError的子類。
-
exception
sqlite3.ProgrammingError? 編程錯誤引發的異常,例如表未找到或已存在,SQL 語句存在語法錯誤,指定的形參數量錯誤等。 它是
DatabaseError的子類。
-
exception
sqlite3.OperationalError? 與數據庫操作相關而不一定能受程序員掌控的錯誤引發的異常,例如發生非預期的連接中斷,數據源名稱未找到,事務無法被執行等。 它是
DatabaseError的子類。
-
exception
sqlite3.NotSupportedError? 在使用了某個數據庫不支持的方法或數據庫 API 時引發的異常,例如在一個不支持事務或禁用了事務的連接上調用
rollback()方法等。 它是DatabaseError的子類。
SQLite 與 Python 類型?
概述?
SQLite 原生支持如下的類型: NULL,INTEGER,REAL,TEXT,BLOB。
因此可以將以下Python類型發送到SQLite而不會出現任何問題:
Python 類型 |
SQLite 類型 |
|---|---|
|
|
|
|
|
|
|
|
|
這是SQLite類型默認轉換為Python類型的方式:
SQLite 類型 |
Python 類型 |
|---|---|
|
|
|
|
|
|
|
取決于 |
|
sqlite3 模塊的類型系統可通過兩種方式來擴展:你可以通過對象適配將額外的 Python 類型保存在 SQLite 數據庫中,你也可以讓 sqlite3 模塊通過轉換器將 SQLite 類型轉換為不同的 Python 類型。
使用適配器將額外的 Python 類型保存在 SQLite 數據庫中。?
如上文所述,SQLite 只包含對有限類型集的原生支持。 要讓 SQLite 能使用其他 Python 類型,你必須將它們 適配 至 sqlite3 模塊所支持的 SQLite 類型中的一種:NoneType, int, float, str, bytes。
有兩種方式能讓 sqlite3 模塊將某個定制的 Python 類型適配為受支持的類型。
讓對象自行調整?
如果自己編寫類,這是一種很好的方法。假設有這樣的類::
class Point:
def __init__(self, x, y):
self.x, self.y = x, y
現在你想將這種點對象保存在一個 SQLite 列中。 首先你必須選擇一種受支持的類型用來表示點對象。 讓我們就用 str 并使用一個分號來分隔坐標值。 然后你需要給你的類加一個方法 __conform__(self, protocol),它必須返回轉換后的值。 形參 protocol 將為 PrepareProtocol。
import sqlite3
class Point:
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])
con.close()
注冊可調用的適配器?
另一種可能的做法是創建一個將該類型轉換為字符串表示的函數并使用 register_adapter() 注冊該函數。
import sqlite3
class Point:
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])
con.close()
sqlite3 模塊有兩個適配器可用于 Python 的內置 datetime.date 和 datetime.datetime 類型。 現在假設我們想要存儲 datetime.datetime 對象,但不是表示為 ISO 格式,而是表示為 Unix 時間戳。
import sqlite3
import datetime
import 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])
con.close()
將SQLite 值轉換為自定義Python 類型?
編寫適配器讓你可以將定制的 Python 類型發送給 SQLite。 但要令它真正有用,我們需要實現從 Python 到 SQLite 再回到 Python 的雙向轉換。
輸入轉換器。
讓我們回到 Point 類。 我們以字符串形式在 SQLite 中存儲了 x 和 y 坐標值。
首先,我們將定義一個轉換器函數,它接受這樣的字符串作為形參并根據該參數構造一個 Point 對象。
注解
轉換器函數在調用時 總是 會附帶一個 bytes 對象,無論你將何種數據類型的值發給 SQLite。
def convert_point(s):
x, y = map(float, s.split(b";"))
return Point(x, y)
現在你需要讓 sqlite3 模塊知道你從數據庫中選取的其實是一個點對象。 有兩種方式都可以做到這件事:
隱式的聲明類型
顯式的通過列名
這兩種方式會在 模塊函數和常量 一節中描述,相應條目為 PARSE_DECLTYPES 和 PARSE_COLNAMES 常量。
下面的示例說明了這兩種方法。
import sqlite3
class Point:
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)).encode('ascii')
def convert_point(s):
x, y = list(map(float, s.split(b";")))
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()
默認適配器和轉換器?
對于 datetime 模塊中的 date 和 datetime 類型已提供了默認的適配器。 它們將會以 ISO 日期/ISO 時間戳的形式發給 SQLite。
默認轉換器使用的注冊名稱是針對 datetime.date 的 "date" 和針對 datetime.datetime 的 "timestamp"。
通過這種方式,你可以在大多數情況下使用 Python 的 date/timestamp 對象而無須任何額外處理。 適配器的格式還與實驗性的 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]))
con.close()
如果存儲在 SQLite 中的時間戳的小數位多于 6 個數字,則時間戳轉換器會將該值截斷至微秒精度。
控制事務?
底層的 sqlite3 庫默認會以 autocommit 模式運行,但 Python 的 sqlite3 模塊默認則不使用此模式。
autocommit 模式意味著修改數據庫的操作會立即生效。 BEGIN 或 SAVEPOINT 語句會禁用 autocommit 模式,而用于結束外層事務的 COMMIT, ROLLBACK 或 RELEASE 則會恢復 autocommit 模式。
Python 的 sqlite3 模塊默認會在數據修改語言 (DML) 類語句 (即 INSERT/UPDATE/DELETE/REPLACE) 之前隱式地執行一條 BEGIN 語句。
你可以控制 sqlite3 隱式執行的 BEGIN 語句的種類,具體做法是通過將 isolation_level 形參傳給 connect() 調用,或者通過指定連接的 isolation_level 屬性。 如果你沒有指定 isolation_level,將使用基本的 BEGIN,它等價于指定 DEFERRED。 其他可能的值為 IMMEDIATE 和 EXCLUSIVE。
你可以禁用 sqlite3 模塊的隱式事務管理,具體做法是將 isolation_level 設為 None。 這將使得下層的 sqlite3 庫采用 autocommit 模式。 隨后你可以通過在代碼中顯式地使用 BEGIN, ROLLBACK, SAVEPOINT 和 RELEASE 語句來完全控制事務狀態。
在 3.6 版更改: 以前 sqlite3 會在 DDL 語句之前隱式地提交未完成事務。 現在則不會再這樣做。
有效使用 sqlite3?
使用快捷方式?
使用 Connection 對象的非標準 execute(), executemany() 和 executescript() 方法,可以更簡潔地編寫代碼,因為不必顯式創建(通常是多余的) Cursor 對象。相反, Cursor 對象是隱式創建的,這些快捷方法返回游標對象。這樣,只需對 Connection 對象調用一次,就能直接執行 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)
print("I just deleted", con.execute("delete from person").rowcount, "rows")
# close is not a shortcut method and it's not called automatically,
# so the connection object should be closed manually
con.close()
通過名稱而不是索引訪問索引?
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"]
con.close()
使用連接作為上下文管理器?
連接對象可以用來作為上下文管理器,它可以自動提交或者回滾事務。如果出現異常,事務會被回滾;否則,事務會被提交。
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")
# Connection object used as context manager only commits or rollbacks transactions,
# so the connection object should be closed manually
con.close()
常見問題?
多線程?
較老版本的 SQLite 在共享線程之間存在連接問題。這就是Python模塊不允許線程之間共享連接和游標的原因。如果仍然嘗試這樣做,則在運行時會出現異常。
唯一的例外是調用 interrupt() 方法,該方法僅在從其他線程進行調用時才有意義。
備注
