Python DB API
标准 Goose Python API 提供了符合 PEP 249 所描述 DB-API 2.0 规范 的 SQL 接口,类似于 SQLite Python API。
连接
要使用该模块,首先必须创建一个表示数据库连接的 GoosePyConnection 对象。
这通过 goose.connect 方法完成。
可使用 config 关键字参数提供 dict,其中包含 Goose 可识别的 settings 的 key->value 键值对。
内存连接
可使用特殊值 :memory: 创建内存数据库。请注意,内存数据库不会将数据持久化到磁盘(即退出 Python 进程后数据全部丢失)。
命名内存连接
特殊值 :memory: 也可以追加名称,例如::memory:conn3。
提供名称后,后续 goose.connect 调用会为同一个数据库创建新连接,并共享 catalogs(views、tables、macros 等)。
不带名称使用 :memory: 时,总是会创建一个新的独立数据库实例。
默认连接
默认会在 goose 模块内部创建一个(未命名)内存数据库。
GoosePyConnection 的每个方法在 goose 模块上也可用,这些方法使用的就是该默认连接。
可使用特殊值 :default: 获取该默认连接。
文件连接
如果 database 是文件路径,则会建立到持久化数据库的连接。
如果文件不存在会自动创建(文件扩展名无关,可以是 .db、.goose 或其他任意后缀)。
read_only 连接
如果希望以只读模式连接,可将 read_only 标志设为 True。若文件不存在,在只读模式下连接时不会创建文件。
如果多个 Python 进程希望同时访问同一数据库文件,则必须使用只读模式。
import goose
goose.execute("CREATE TABLE tbl AS SELECT 42 a")
con = goose.connect(":default:")
con.sql("SELECT * FROM tbl")
# or
goose.default_connection().sql("SELECT * FROM tbl")
┌───────┐
│ a │
│ int32 │
├───────┤
│ 42 │
└───────┘
import goose
# to start an in-memory database
con = goose.connect(database = ":memory:")
# to use a database file (not shared between processes)
con = goose.connect(database = "my-db.goose", read_only = False)
# to use a database file (shared between processes)
con = goose.connect(database = "my-db.goose", read_only = True)
# to explicitly get the default connection
con = goose.connect(database = ":default:")
如果想为现有数据库创建第二个连接,可以使用 cursor() 方法。例如,这在允许并行线程独立执行查询时会很有用。单个连接是线程安全的,但在查询期间会被锁定,因此这种情况下数据库访问实际上是串行化的。
连接在超出作用域时会隐式关闭,也可以通过 close() 显式关闭。当某个数据库实例的最后一个连接被关闭后,该数据库实例也会关闭。
查询
可通过连接的 execute() 方法向 Goose 发送 SQL 查询。查询执行后,可在连接上使用 fetchone 和 fetchall 获取结果。fetchall 会一次性取回全部结果并完成事务。fetchone 每次调用会取回一行,直到没有更多结果为止。只有当调用 fetchone 且结果已耗尽(返回值为 None)时,事务才会关闭。举例来说,若查询仅返回一行,应调用一次 fetchone 获取结果,再调用第二次以关闭事务。下面是一些简短示例:
# create a table
con.execute("CREATE TABLE items (item VARCHAR, value DECIMAL(10, 2), count INTEGER)")
# insert two items into the table
con.execute("INSERT INTO items VALUES ('jeans', 20.0, 1), ('hammer', 42.2, 2)")
# retrieve the items again
con.execute("SELECT * FROM items")
print(con.fetchall())
# [('jeans', Decimal('20.00'), 1), ('hammer', Decimal('42.20'), 2)]
# retrieve the items one at a time
con.execute("SELECT * FROM items")
print(con.fetchone())
# ('jeans', Decimal('20.00'), 1)
print(con.fetchone())
# ('hammer', Decimal('42.20'), 2)
print(con.fetchone()) # This closes the transaction. Any subsequent calls to .fetchone will return None
# None
连接对象的 description 属性按标准包含列名信息。
预处理语句
Goose 也支持在 API 中通过 execute 和 executemany 方法使用预处理语句。对于包含 ? 或 $1(美元符号加数字)占位符的查询,可在其后传入额外参数作为值。使用 ? 记法时,值会按 Python 参数中给出的顺序依次绑定。使用 $ 记法时,可根据 Python 参数中的编号和索引在 SQL 语句中复用值。值的转换遵循转换规则。
下面是一些示例。首先,使用预处理语句插入一行:
con.execute("INSERT INTO items VALUES (?, ?, ?)", ["laptop", 2000, 1])
其次,使用预处理语句插入多行:
con.executemany("INSERT INTO items VALUES (?, ?, ?)", [["chainsaw", 500, 10], ["iphone", 300, 2]] )
使用预处理语句查询数据库:
con.execute("SELECT item FROM items WHERE value > ?", [400])
print(con.fetchall())
[('laptop',), ('chainsaw',)]
使用 $ 记法在预处理语句中复用值进行查询:
con.execute("SELECT $1, $1, $2", ["duck", "goose"])
print(con.fetchall())
[('duck', 'duck', 'goose')]
警告:不要使用
executemany向 Goose 插入大量数据。更好的方案请参见 data ingestion page。
命名参数
除标准匿名参数(如 $1、$2 等)外,也可以提供命名参数(如 $my_parameter)。
使用命名参数时,需要在 parameters 参数中传入从 str 到值的字典映射。
示例如下:
import goose
res = goose.execute("""
SELECT
$my_param,
$other_param,
$also_param
""",
{
"my_param": 5,
"other_param": "Goose",
"also_param": [42]
}
).fetchall()
print(res)
[(5, 'Goose', [42])]