sqlite 在 Python 下的再封裝
原來一直使用 MongoDB 作為主力數(shù)據(jù)庫,但是單位的電腦是 32 位的機(jī)器,有單一數(shù)據(jù)庫的限制,故一直在尋找替代品。最近發(fā)現(xiàn)原來 sqlite 用起來也不錯(cuò),其 api 簡潔明了。另外,作為一個(gè)文件型數(shù)據(jù)庫, Python 自帶,不需要安裝服務(wù)器軟件,用起來非常方便,并且也不存在安全隱患。
由于本人經(jīng)常寫命令行的軟件,故需要對(duì)系統(tǒng)提供的 api 再進(jìn)一步封裝,更加方便自己的使用。
程序的封裝 sqlite.py
文件頭
import atexit
import sqlite3
from contextlib import contextmanager, closing
from pathlib import Path
_conn = None
_config = {}
db_config
def db_config(database: str, **kw):
global _config
kw['database'] = str(database)
_config = kw
connect
def connect():
global _conn
if not _conn:
_conn = sqlite3.connect(**_config)
atexit.register(_conn.close)
return _conn
trans
@contextmanager
def trans():
try:
conn = connect()
yield
conn.commit()
except Exception as e:
conn.rollback()
raise e
execute
def execute(sql: str, params: list = []):
return connect().execute(sql, params)
executemany
def executemany(sql: str, params: list = []):
return connect().executemany(sql, params)
executescript
def executescript(sql: str):
return connect().executescript(sql)
executefile
def executefile(pkg: str, filename: str):
'''
執(zhí)行程序中附帶的資源文件
pkg : 所在包的名稱
filename : 相關(guān)于包的文件名,包括路徑
'''
from pkgutil import get_data
data = get_data(pkg, filename)
sql = data.decode('utf8')
return executescript(sql)
find
def find(sql: str, params: list = [], multi=True):
'''執(zhí)行sql 語句,并返行多行或一行記錄'''
cur = execute(sql, params)
with closing(cur):
return cur.fetchall()if multi else cur.fetchone()
findone
def findone(sql: str, params: list = []):
'''執(zhí)行 sql 語句,并返回一行記錄'''
return find(sql, params, multi=False)
findvalue
def findvalue(sql: str, params: list = []):
'''執(zhí)行 sql 語句,并返回一個(gè)值 '''
row = findone(sql, params)
return row and row[0]
具體使用方法
經(jīng)過封裝后,執(zhí)行數(shù)據(jù)庫指令或查詢時(shí)不用調(diào)用 connect 來連接數(shù)據(jù)庫,先用 db_config來設(shè)置好 connect的參數(shù)就行了。后面的程序在執(zhí)行數(shù)據(jù)庫命令或查詢語句的時(shí)候會(huì)自動(dòng)連接,并在程序退出的時(shí)候自帶關(guān)閉(使用 atexit來實(shí)現(xiàn))。
配置連接參數(shù)
調(diào)用 db_config就行了,其參數(shù)與 sqlite3 庫中的 connect的參數(shù)完全一致。使用方法如下:
db_config(':memory:')
執(zhí)行 sql 語句
共有四條命令可用,其用途如下:
- execute:沒有參數(shù)或只有一行參數(shù)時(shí)使用
- executemay:同一條語句多行參數(shù)時(shí)使用
- executescript:執(zhí)行多條語句,并且無參數(shù)時(shí)使用,一般在定義表或刪除表的時(shí)候使用
- executefile:執(zhí)行多條語句,并且語句以包數(shù)據(jù)文件的時(shí)候使用
注意: execute 和 executemany 需要在 trans 環(huán)境下執(zhí)行,同一個(gè)trans下全部執(zhí)行成功則提交服務(wù)器,執(zhí)行中存在異常則全部回滾。如果不在 trans環(huán)境下執(zhí)行,則連接關(guān)閉后修改的數(shù)據(jù)完全丟失。executescript 和 executefile不需要在 trans環(huán)境下執(zhí)行,會(huì)自動(dòng)提交。故只應(yīng)使用 DDL 語句,而不應(yīng)該插入或修改數(shù)據(jù) 。
具體示例:
建表文件:test.sql
create table if not exists test(
id int primary key,
name text,
age int
);
create table if not exists school(
userid int primary key,
class text
)
執(zhí)行語句示例
db_config(':memory:')
executescript('drop table if exists test;'
'drop table if exists school;')
executefile('pkg','test.sql')
with trans():
execute('insert into test values(?,?,?)',[1,'Tom',23])
executemany('insert into test values(?,?,?)',[
[2,'Alice',22],
[3,'John',21]])
查詢語句
執(zhí)行查詢可以使用 find、findone 和findvalue三個(gè)命令,其差異如下:
- find: 執(zhí)行查詢后提取多行數(shù)據(jù)
- findone: 執(zhí)行查詢后只提取第一行數(shù)據(jù)
- findvalue:執(zhí)行查詢后只提取第一行數(shù)據(jù)的第一個(gè)值
使用示例:
usercount=findvalue('select count(id) from test')
id,name,age=findone('select * from test where name=?',['tom'])
for id,name,age in find('select * from test'):
print(id,name,age)
結(jié)語
使用上述方法進(jìn)行封裝后,調(diào)用 sqlite 更加簡潔,避免了數(shù)據(jù)庫連接和關(guān)閉。并且執(zhí)行查詢所產(chǎn)生的cursor均可以自動(dòng)關(guān)閉。