Twisted的关系数据库支持(Twisted RDBMS support)

-- Jerry Marx [2004-09-15 04:30:49]

概要(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)

快速回顾(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.
  11 

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类来管理你的数据库连接,而不要直接连接.这个类可以使用多个连接,比方说每个线程一个连接,非常容易:

   1 # Using the "dbmodule" from the previous example, create a ConnectionPool 
   2 from twisted.enterprise import adbapi 
   3 dbpool = adbapi.ConnectionPool("dbmodule", 'mydb', 'andrew', 'password')
   4 

Things to note about doing this:

这么做的时候要注意以下这些事情:

Now we can do a database query:

现在我们可以做数据库查询了:

   1 # equivalent of cursor.execute(statement), return cursor.fetchall():
   2 def getAge(user):
   3     return dbpool.runQuery("SELECT age FROM users WHERE name = ?", user)
   4 
   5 def printResult(l):
   6     if l:
   7         print l[0][0], "years old"
   8     else:
   9         print "No such user"
  10 
  11 getAge("joe").addCallback(printResult)
  12 

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)
  22 

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模块的问道那个来获得另一些函数的信息,希望这个文档给了你基本的概念.

"目录(Index)"

version 1.3.0

PyTwisted/TwistedUtilities/TwistedRdbmsSupport (last edited 2009-12-25 07:18:21 by localhost)