RQLite 的非官方 python 客户端
项目描述
rqdb
这是rqlite的非官方 python 客户端,一个基于 SQLite 的轻量级分布式关系数据库。
此客户端支持 SQLite 语法、真正的参数化查询和让人想起 DB API 2.0 的调用语法。
此外,此客户端具有与底层 rqlite API 匹配的便捷异步方法。
安装
pip install rqdb
用法
同步查询:
import rqdb
import secrets
conn = rqdb.connect(['127.0.0.1:4001'])
cursor = conn.cursor()
cursor.execute('CREATE TABLE persons (id INTEGER PRIMARY KEY, uid TEXT UNIQUE NOT NULL, name TEXT NOT NULL)')
cursor.execute('CREATE TABLE pets (id INTEGER PRIMARY KEY, name TEXT NOT NULL, owner_id INTEGER NOT NULL REFERENCES persons(id) ON DELETE CASCADE)')
# standard execute
cursor.execute('INSERT INTO persons (uid, name) VALUES (?, ?)', (secrets.token_hex(8), 'Jane Doe'))
assert cursor.rows_affected == 1
# The following is stored in a single Raft entry and executed within a transaction.
person_name = 'John Doe'
person_uid = secrets.token_urlsafe(16)
pet_name = 'Fido'
result = cursor.executemany3((
(
'INSERT INTO persons (uid, name) VALUES (?, ?)',
(person_uid, person_name)
),
(
'INSERT INTO pets (name, owner_id) '
'SELECT'
' ?, persons.id '
'FROM persons '
'WHERE uid = ?',
(pet_name, person_uid)
)
)).raise_on_error()
assert result[0].rows_affected == 1
assert result[1].rows_affected == 1
异步查询:
import rqdb
import secrets
async def main():
async with rqdb.connect_async(['127.0.0.1:4001']) as conn:
cursor = conn.cursor()
result = await cursor.execute(
'INSERT INTO persons (uid, name) VALUES (?, ?)',
(secrets.token_hex(8), 'Jane Doe')
)
assert result.rows_affected == 1
附加的功能
读取一致性
在游标级别选择读取一致性,可以通过传递
read_consistency给游标构造函数 ( conn.cursor()) 或直接设置实例变量read_consistency。可用的一致性是strong、weak和none。您还可以freshness在光标级别指示值。
有关详细信息,请参阅CONSISTENCY.md。
默认一致性是weak.
外键
rqlite 中的外键支持默认禁用,以匹配 sqlite。这是一个常见的混淆来源。它不能由客户端可靠地配置。如 FOREIGN_KEY_CONSTRAINTS.md中所述启用外键支持
空值
在参数化查询中替换“NULL”可能容易出错。特别是,sqlite 需要以非常特殊的方式发送 null,而 rqlite 服务器历来没有正确处理。
默认情况下,如果您尝试使用“None”作为查询的参数,此包将在正确的位置执行值为“NULL”的字符串替换。但是要小心 - 您仍然需要在查询中正确处理空值,因为“col = NULL”和“col IS NULL”不一样。特别NULL = NULL
是 is NULL,它的计算结果为假。一种可以处理的方法是
name: Optional[str] = None
# never matches a row since name is None, even if the rows name is null
cursor.execute('SELECT * FROM persons WHERE name = ?', (name,))
# works as expected
cursor.execute('SELECT * FROM persons WHERE ((? IS NULL AND name IS NULL) OR name = ?)', (name, name))
备份
可以使用 启动备份conn.backup(filepath: str, raw: bool = False)。下载将流式传输到给定的文件路径。支持 sql 格式和压缩的 sqlite 格式。
日志记录
默认情况下,这将使用标准logging模块记录。这可以log=False在connect通话中禁用。如果需要记录但只需要稍微配置,可以按如下方式完成:
import rqdb
import logging
conn = rqdb.connect(
['127.0.0.1:4001'],
log=rqdb.LogConfig(
# Started a SELECT query
read_start={
'enabled': True,
'level': logging.DEBUG, # alternatively, 'method': logging.debug
},
# Started a UPDATE/INSERT query
write_start={
'enabled': True,
'level': logging.DEBUG,
},
# Got the response from the database for a SELECT query
read_response={
'enabled': True,
'level': logging.DEBUG,,
'max_length': 1024, # limits how much of the response we log
},
# Got the response from the database for a UPDATE/INSERT query
write_response={
'enabled': True,
'level': logging.DEBUG,
},
# Failed to connect to one of the nodes.
connect_timeout={
'enabled': True,
'level': logging.WARNING,
},
# Failed to connect to any node for a query
hosts_exhausted={
'enabled': True,
'level': logging.CRITICAL,
},
# The node returned a status code other than 200-299 or
# a redirect when a redirect is allowed.
non_ok_response={
'enabled': True,
'level': logging.WARNING
}
)
)
限制
交易缓慢
主要限制是由于 rqlite 的无连接特性,虽然事务是可能的,但必须预先指定整个事务。也就是说,您不能打开事务、执行查询,然后在关闭事务之前使用该查询的结果执行另一个查询。
这也可以看作是一种祝福,因为这些类型的事务是传统应用程序中最常见的性能问题来源。它们需要很容易导致 N^2 性能的长期持有的锁。使用 uid 几乎总是可以实现相同的行为,如示例中所示。重复的 UID 查找会导致一致的开销,这对于长事务的不可预测的负反馈循环性质非常可取。
其他注意事项
在处理复杂查询时,将此库与pypika等 sql 构建器结合起来通常很有帮助。
项目详情
下载文件
下载适用于您平台的文件。如果您不确定要选择哪个,请了解有关安装包的更多信息。