熬着熬着,让时间熬成想要的那个自己,一个美丽的人。
分类: Python/Ruby
2014-02-18 19:12:21
因为Twisted的应用是事件循环,应用必须不能在主线程阻塞调用,否则整个事件循环会停止。因为大多数数据库暴露了一个阻塞的API,Twisted提供了twisted.enterprise.adbapi作为一个非阻塞的接口给DB-API-2.0由python捆绑实现的可适用于大多数主流数据库,包括MySQL,Postgres和SQLite。
非阻塞数据查询
从阻塞的API到adbapi是一个直接转换的方式:不是创建独立的数据库连接,而是用一个adbapi.ConnectionPool的连接来管理一个连接池,连接用独立的线程。一旦有了数据库游标,不是用阻塞执行取回方法,而是用dbpool.runQuery来执行一个SQL查询并返回结果。
Example8-1解释了一个非阻塞的SELECT查询,基于一个假设的SQLite数据库--users.db(错误返回已经被省略,为了简洁)
注:如果使用SQLite的接口adbapi过程中遇到如下的错误信息:
你需要在创建ConnectionPool时设定check_same_thread=False,比如如下:
Dbpool = adbapi.ConnectionPool(’sqlite3’,’users.db’,check_same_thread=False)
参考Twisted ticket 3629详述。
adbapi.ConnectionPool的第一个参数是所绑定的数据库所需要的重要字符串。其他的参数传给绑定的数据库的相应连接方法,这是根据所选择的数据库不同而有所不同。比如说,连接一个MySQL数据库可能会这样adbapi.ConnectionPool(‘MySQLdb’,db=‘users’)。
dbpool.runQuery返回一个Deferred,因此我们能调用callbacks和errbacks来处理查询结果,就跟前面章节我们用过的Deferred一样。你最可能用到这个API的部分莫过于阻塞这里:
adbapi.ConnectionPool()
Connection=db-module.connect()由cursor=connection.cursor()跟踪
runOperation()
Cursor.execute()
runQuery()
Cursor.execute()由cursor.fetchall()跟踪
runInteraction()
在一个事件中运行多个查询
注意一下,因为我们用了ConnectionPool,我们不需要关注连接或者关闭连接数据库。
Example8-2用runInteraction从前一个例子基础上创建了SQLite的users数据库表。
注意下,dbpool.runInteraction调用的函数用了默认的数据库驱动的阻塞游标,在不同的线程里运行,因此必须是安全的线程方法。
dbpool.runInteraction返回了一个Deferred.在这个例子里面,_createUsersTable函数没有返回,这样Twisted就认为是合理的,从而触发了回调链里面的第一个callback。
更多练习和下一步计划
这一章节介绍了如何以非阻塞的方式跟数据库交互,即应用Twisted的adbapi。Adbapi提供了一个异步的接口给Python 的DB-API2.0标准,是在PEP249定义的。异步接口的方法直接映射给了阻塞API的方法,因此从阻塞数据库查询中转换一个服务到adbapi是很直观的。
有一个实例是更大的项目运用了Twisted的相关数据库支持,可参阅Buildbot 数据库持续集成框架。