Twisted的关系数据库支持(Twisted RDBMS support)
-- Jerry Marx [2004-09-15 04:30:49]
Contents
概要(Abstract)
Twisted is an asynchronous networking framework, but most database API implementations unfortunately have blocking interfaces -- for this reason, twisted.enterprise.adbapi was created. It is a non-blocking interface to the standardized DB-API 2.0 API, which allows you to access a number of different RDBMSes.
Twisted是异步的网络编程框架,不幸的是大多数数据库API的实现都是阻塞的接口,因为这个原因创造了twisted.enterprise.adbapi.它是一个符合DB-API 2.0 标准的非阻塞接口,使用它可以访问很多关系数据库
你应该已经知道的(What you should already know)
Python
- How to write a simple Twisted Server (see this tutorial to learn how) 如何用Twisted写一个简单的Server(参见教程学习如何做)
- Familiarity with using database interfaces (see the documentation for DBAPI 2.0 or this article by Andrew Kuchling) 对使用数据库接口很熟悉(参见DBAPI 2.0 的文档或者由 Andrew Kuchling 写的这份文档)
快速回顾(Quick Overview)
Twisted is an asynchronous framework. This means standard database modules cannot be used directly, as they typically work something like:
Twisted是一个异步编程框架,这就意味着标准的数据库模块不能直接使用,他们的典型用法如下:
1 # Create connection...
2 db = dbmodule.connect('mydb', 'andrew', 'password')
3 # ...which blocks for an unknown amount of time
4
5 # Create a cursor
6 cursor = db.cursor()
7
8 # Do a query...
9 resultset = cursor.query('SELECT * FROM table WHERE ...')
10 # ...which could take a long time, perhaps even minutes.
Those delays are unacceptable when using an asynchronous framework such as Twisted. For this reason, twisted provides twisted.enterprise.adbapi, an asynchronous wrapper for any DB-API 2.0-compliant module.
对于像Twisted这样的异步编程框架来说延迟是不能接受的.因为这个原因,twisted提供了twisted.enterprise.adbapi,它是一个对于任何兼容DB-API 2.0 的异步包装模块.
enterprise.adbapi will do blocking database operations in seperate threads, which trigger callbacks in the originating thread when they complete. In the meantime, the original thread can continue doing normal work, like servicing other requests.
enterprise.adbapi在独立的线程里面执行阻塞的数据库操作,而是在操作完成后触发原线程的回调函数.同时,原始线程可以继续执行,比方说处理其他的请求.
怎么使用adbapi(How do I use adbapi?)
Rather than creating a database connection directly, use the adbapi.ConnectionPool class to manage a connections for you. This allows enterprise.adbapi to use multiple connections, one per thread. This is easy:
使用adbapi.ConnectionPool类来管理你的数据库连接,而不要直接连接.这个类可以使用多个连接,比方说每个线程一个连接,非常容易:
Things to note about doing this:
这么做的时候要注意以下这些事情:
There is no need to import dbmodule directly. You just pass the name to adbapi.ConnectionPool's constructor.
The parameters you would pass to dbmodule.connect are passed as extra arguments to adbapi.ConnectionPool's constructor. Keyword parameters work as well.
不需要直接import dbmodule.只需要把名称传递给adbapi.ConnectionPool的构造函数.
要传递给dbmodule.connect的参数就是传递给adbapi.ConnectionPool的构造函数的参数,关键字参数可以很好的工作.
Now we can do a database query:
现在我们可以做数据库查询了:
This is straightforward, except perhaps for the return value of getAge. It returns a twisted.internet.defer.Deferred, which allows arbitrary callbacks to be called upon completion (or upon failure). More documentation on Deferred is available here.
除了getAge的返回值可能有些奇怪以外,上面的代码一目了然.getAge返回了一个twisted.internet.defer.Deferred,可以给它添加任何的成功回调(或者错误回调).关于Deferred的更多信息可以查阅文档.
In addition to runQuery, there is also runOperation, and runInteraction that gets called with a callable (e.g. a function). The function will be called in the thread with a twisted.enterprise.adbapi.Transaction, which basically mimics a DB-API cursor. In all cases a database transaction will be commited after your database usage is finished, unless an exception is raised in which case it will be rolled back.
除了runQuery外,还有runOperation和runInteraction可以杯一个可调用实体(比方说一个函数)来调用.这个函数会在一个拥有twisted.enterprise.adbapi.Transaction的线程里调用,它简单模拟了一个DB-API游标.
1 def _getAge(txn, user):
2 # this will run in a thread, we can use blocking calls
3 txn.execute("SELECT * FROM foo")
4 # ... other cursor commands called on txn ...
5 txn.execute("SELECT age FROM users WHERE name = ?", user)
6 result = txn.fetchall()
7 if result:
8 return result[0][0]
9 else:
10 return None
11
12 def getAge(user):
13 return dbpool.runInteraction(_getAge, user)
14
15 def printResult(age):
16 if age != None:
17 print age, "years old"
18 else:
19 print "No such user"
20
21 getAge("joe").addCallback(printResult)
Also worth noting is that these examples assumes that dbmodule uses the qmarks paramstyle (see the DB-API specification). If your dbmodule uses a different paramstyle (e.g. pyformat) then use that. Twisted doesn't attempt to offer any sort of magic paramater munging -- runQuery(query, params, ...) maps directly onto cursor.execute(query, params, ...).
另外还要注意这个例子假设dbmodule使用qmarks paramstyle(参见DB-API规范).如果你的dbmodule使用了不同的paramstyle(比方说pyformat)你就要改相应的地方.Twisted没有提供任何参数排序 -- runQuery(query, params, ...)直接映射到cursor.execute(query, params, ...).
这样!(And that's it!)
That's all you need to know to use a database from within Twisted. You probably should read the adbapi module's documentation to get an idea of the other functions it has, but hopefully this document presents the core ideas.
以上就是在Twisted种使用数据库需要知道的全部知识.你或许应该阅读adbapi模块的问道那个来获得另一些函数的信息,希望这个文档给了你基本的概念.
- 翻译 -- Jerry Marx
version 1.3.0