Chapter 8. Databases

Because Twisted applications run in an event loop, the application must not make blocking calls in the main thread or the entire event loop will stall. Because most databases expose a blocking API, Twisted provides twisted.enterprise.adbapi as a non-blocking interface to the DB-API 2.0 API implemented by Python bindings for most popular databases, including MySQL, Postgres, and SQLite.

Switching from the blocking API to adbapi is a straightforward transformation: instead of creating individual database connections, use a connection from adbapi.ConnectionPool, which manages a pool of connections run in separate threads for you. Once you have a database cursor, instead of using the blocking execute and fetchall methods, use dbpool.runQuery to execute a SQL query and return the result.

Example 8-1 demonstrates executing a nonblocking SELECT query on a hypothetical SQLite database called users.db (the errback has been omitted for brevity).

The first argument to adbapi.ConnectPool is the import string for the desired database bindings. The rest of the arguments are passed to the underlying connect method for your database bindings and thus differ based on which database you are using. For example, connecting to a MySQL database might look like adbapi.ConnectionPool("MySQLdb", db="users").

dbpool.runQuery returns a Deferred, so we can attach callbacks and errbacks for processing the result of the query just as we’ve done with Deferreds in previous chapters.

The parts of the API you are most likely to use map neatly to blocking counterparts:

Note that because we are using a ConnectionPool, we don’t have to take care of connecting to or disconnecting from the database.

Example 8-2 uses runInteraction to create the SQLite users database from Example 8-1.

Note that the function called by dbpool.runInteraction uses the blocking cursor methods of the underlying database driver and runs in a separate thread. It must be a thread-safe function.

dbpool.runInteraction returns a Deferred. In this example, _createUsersTable implicitly returns None, which Twisted considers success, invoking the first callback in the callback chain.

This chapter discussed how to interact with databases in a non-blocking fashion using Twisted’s adbapi. adbapi provides an asynchronous interface to Python’s DB-API 2.0 specification, which is defined in PEP 249. The methods in the asynchronous interface map directly to methods in the blocking API, so converting a service from blocking database queries to adbapi is straightforward.

For an example of how a large project uses Twisted’s relational database support, check out the Buildbot continuous integration framework.

Twistar is a library that builds an object-relational mapper (ORM) on top of adbapi.