twisted.enterprise.adbapi:Twisted RDBMS 支持¶
摘要¶
Twisted 是一个异步网络框架,但大多数数据库 API 实现不幸地具有阻塞接口 - 因此,twisted.enterprise.adbapi
应运而生。它是一个针对标准化 DB-API 2.0 API 的非阻塞接口,允许您访问许多不同的 RDBMS。
您应该已经了解的内容¶
Python :-)
如何编写一个简单的 Twisted 服务器(请参阅 本教程 了解如何编写)
熟悉使用数据库接口(请参阅 DBAPI 2.0 文档)
快速概述¶
Twisted 是一个异步框架。这意味着无法直接使用标准数据库模块,因为它们通常的工作方式类似于
# Create connection...
db = dbmodule.connect('mydb', 'andrew', 'password')
# ...which blocks for an unknown amount of time
# Create a cursor
cursor = db.cursor()
# Do a query...
resultset = cursor.query('SELECT * FROM table WHERE ...')
# ...which could take a long time, perhaps even minutes.
当使用像 Twisted 这样的异步框架时,这些延迟是不可接受的。为此,Twisted 提供了 twisted.enterprise.adbapi
,它是任何 DB-API 2.0 兼容模块的异步包装器。
adbapi
将在单独的线程中执行阻塞数据库操作,这些操作在完成时会在源线程中触发回调。在此期间,源线程可以继续执行正常工作,例如服务其他请求。
如何使用 adbapi?¶
不要直接创建数据库连接,而是使用 adbapi.ConnectionPool
类来为您管理连接。这允许 adbapi
使用多个连接,每个线程一个。这很简单
# Using the "dbmodule" from the previous example, create a ConnectionPool
from twisted.enterprise import adbapi
dbpool = adbapi.ConnectionPool("dbmodule", 'mydb', 'andrew', 'password')
关于执行此操作需要注意的事项
无需直接导入 dbmodule。您只需将名称传递给
adbapi.ConnectionPool
的构造函数。您传递给 dbmodule.connect 的参数作为额外的参数传递给
adbapi.ConnectionPool
的构造函数。关键字参数也适用。
现在我们可以执行数据库查询了
# equivalent of cursor.execute(statement), return cursor.fetchall():
def getAge(user):
return dbpool.runQuery("SELECT age FROM users WHERE name = ?", user)
def printResult(l):
if l:
print(l[0][0], "years old")
else:
print("No such user")
getAge("joe").addCallback(printResult)
这很简单,除了 getAge
的返回值。它返回一个 Deferred
,它允许在完成(或失败)时调用任意回调。有关 Deferred 的更多文档,请参阅 此处。
除了 runQuery
之外,还有 runOperation
和 runInteraction
,它们会使用可调用对象(例如函数)进行调用。该函数将在具有 adbapi.Transaction
的线程中调用,该线程基本上模拟了 DB-API 游标。在所有情况下,数据库事务将在您的数据库使用完成后提交,除非引发异常,在这种情况下,它将回滚。
def _getAge(txn, user):
# this will run in a thread, we can use blocking calls
txn.execute("SELECT * FROM foo")
# ... other cursor commands called on txn ...
txn.execute("SELECT age FROM users WHERE name = ?", user)
result = txn.fetchall()
if result:
return result[0][0]
else:
return None
def getAge(user):
return dbpool.runInteraction(_getAge, user)
def printResult(age):
if age != None:
print(age, "years old")
else:
print("No such user")
getAge("joe").addCallback(printResult)
还需要注意的是,这些示例假设 dbmodule 使用“qmarks”paramstyle(请参阅 DB-API 规范)。如果您的 dbmodule 使用不同的 paramstyle(例如 pyformat),则使用它。Twisted 不会尝试提供任何神奇的参数整理 - runQuery(query, params, ...)
直接映射到 cursor.execute(query, params, ...)
。
各种数据库适配器的示例¶
请注意,第一个参数是您通常导入并从中获取 connect(...)
的模块名称,后面的参数是您调用 connect(...)
时使用的任何参数。
from twisted.enterprise import adbapi
# PostgreSQL PyPgSQL
cp = adbapi.ConnectionPool("pyPgSQL.PgSQL", database="test")
# MySQL
cp = adbapi.ConnectionPool("MySQLdb", db="test")
就是这样!¶
这就是您在 Twisted 中使用数据库所需了解的全部内容。您可能应该阅读 adbapi 模块的文档,以了解它具有的其他函数,但希望本文档能介绍核心思想。