enterprise.html   [plain text]


<?xml version="1.0"?><!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><html xmlns="http://www.w3.org/1999/xhtml" lang="en"><head><title>Twisted Documentation: Twisted RDBMS support</title><link href="../howto/stylesheet.css" type="text/css" rel="stylesheet" /></head><body bgcolor="white"><h1 class="title">Twisted RDBMS support</h1><div class="toc"><ol><li><a href="#auto0">Abstract</a></li><li><a href="#auto1">What you should already know</a></li><li><a href="#auto2">Quick Overview</a></li><li><a href="#auto3">How do I use adbapi?</a></li><li><a href="#auto4">And that's it!</a></li></ol></div><div class="content"><span></span><h2>Abstract<a name="auto0"></a></h2><p>Twisted is an asynchronous networking framework, but most
    database API implementations unfortunately have blocking
    interfaces -- for this reason, <code class="API"><a href="http://twistedmatrix.com/documents/TwistedDocs/TwistedDocs-1.3.0/api/twisted.enterprise.adbapi.html" title="twisted.enterprise.adbapi">twisted.enterprise.adbapi</a></code> 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.</p><h2>What you should already know<a name="auto1"></a></h2><ul><li>Python :-)</li><li>How to write a simple Twisted Server (see <a href="servers.html">this tutorial</a> to learn how)</li><li>Familiarity with using database interfaces (see <a href="http://www.python.org/topics/database/DatabaseAPI-2.0.html">
      the documentation for DBAPI 2.0</a> or this <a href="http://www.amk.ca/python/writing/DB-API.html">article</a>
      by Andrew Kuchling)</li></ul><h2>Quick Overview<a name="auto2"></a></h2><p>Twisted is an asynchronous framework. This means standard
    database modules cannot be used directly, as they typically
    work something like:</p><pre class="python">
<span class="py-src-comment"># Create connection... 
</span><span class="py-src-variable">db</span> <span class="py-src-op">=</span> <span class="py-src-variable">dbmodule</span><span class="py-src-op">.</span><span class="py-src-variable">connect</span><span class="py-src-op">(</span><span class="py-src-string">'mydb'</span><span class="py-src-op">,</span> <span class="py-src-string">'andrew'</span><span class="py-src-op">,</span> <span class="py-src-string">'password'</span><span class="py-src-op">)</span> <span class="py-src-newline">
</span><span class="py-src-comment"># ...which blocks for an unknown amount of time 
</span> <span class="py-src-nl">
</span><span class="py-src-comment"># Create a cursor 
</span><span class="py-src-variable">cursor</span> <span class="py-src-op">=</span> <span class="py-src-variable">db</span><span class="py-src-op">.</span><span class="py-src-variable">cursor</span><span class="py-src-op">(</span><span class="py-src-op">)</span> <span class="py-src-newline">
</span> <span class="py-src-nl">
</span><span class="py-src-comment"># Do a query... 
</span><span class="py-src-variable">resultset</span> <span class="py-src-op">=</span> <span class="py-src-variable">cursor</span><span class="py-src-op">.</span><span class="py-src-variable">query</span><span class="py-src-op">(</span><span class="py-src-string">'SELECT * FROM table WHERE ...'</span><span class="py-src-op">)</span> <span class="py-src-newline">
</span><span class="py-src-comment"># ...which could take a long time, perhaps even minutes.
</span><span class="py-src-endmarker"></span></pre><p>Those delays are unacceptable when using an asynchronous
    framework such as Twisted. For this reason, twisted provides
    <code class="API"><a href="http://twistedmatrix.com/documents/TwistedDocs/TwistedDocs-1.3.0/api/twisted.enterprise.adbapi.html" title="twisted.enterprise.adbapi">twisted.enterprise.adbapi</a></code>, an
    asynchronous wrapper for any <a href="http://www.python.org/topics/database/DatabaseAPI-2.0.html">
    DB-API 2.0</a>-compliant module.</p><p><code class="API"><a href="http://twistedmatrix.com/documents/TwistedDocs/TwistedDocs-1.3.0/api/twisted.enterprise.adbapi.html" title="twisted.enterprise.adbapi">enterprise.adbapi</a></code> 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.</p><h2>How do I use adbapi?<a name="auto3"></a></h2><p>Rather than creating a database connection directly, use the
    <code class="API"><a href="http://twistedmatrix.com/documents/TwistedDocs/TwistedDocs-1.3.0/api/twisted.enterprise.adbapi.ConnectionPool.html" title="twisted.enterprise.adbapi.ConnectionPool">adbapi.ConnectionPool</a></code>
    class to manage
    a connections for you. This allows <code class="API"><a href="http://twistedmatrix.com/documents/TwistedDocs/TwistedDocs-1.3.0/api/twisted.enterprise.adbapi.html" title="twisted.enterprise.adbapi">enterprise.adbapi</a></code> to use multiple
    connections, one per thread. This is easy:</p><pre class="python">
<span class="py-src-comment"># Using the &quot;dbmodule&quot; from the previous example, create a ConnectionPool 
</span><span class="py-src-keyword">from</span> <span class="py-src-variable">twisted</span><span class="py-src-op">.</span><span class="py-src-variable">enterprise</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">adbapi</span> <span class="py-src-newline">
</span><span class="py-src-variable">dbpool</span> <span class="py-src-op">=</span> <span class="py-src-variable">adbapi</span><span class="py-src-op">.</span><span class="py-src-variable">ConnectionPool</span><span class="py-src-op">(</span><span class="py-src-string">&quot;dbmodule&quot;</span><span class="py-src-op">,</span> <span class="py-src-string">'mydb'</span><span class="py-src-op">,</span> <span class="py-src-string">'andrew'</span><span class="py-src-op">,</span> <span class="py-src-string">'password'</span><span class="py-src-op">)</span><span class="py-src-newline">
</span><span class="py-src-endmarker"></span></pre><p>Things to note about doing this:</p><ul><li>There is no need to import dbmodule directly. You just
      pass the name to <code class="API"><a href="http://twistedmatrix.com/documents/TwistedDocs/TwistedDocs-1.3.0/api/twisted.enterprise.adbapi.ConnectionPool.html" title="twisted.enterprise.adbapi.ConnectionPool">adbapi.ConnectionPool</a></code>'s constructor.</li><li>The parameters you would pass to dbmodule.connect are
      passed as extra arguments to <code class="API"><a href="http://twistedmatrix.com/documents/TwistedDocs/TwistedDocs-1.3.0/api/twisted.enterprise.adbapi.ConnectionPool.html" title="twisted.enterprise.adbapi.ConnectionPool">adbapi.ConnectionPool</a></code>'s constructor.
      Keyword parameters work as well.</li></ul><p>Now we can do a database query:</p><pre class="python">
<span class="py-src-comment"># equivalent of cursor.execute(statement), return cursor.fetchall():
</span><span class="py-src-keyword">def</span> <span class="py-src-identifier">getAge</span><span class="py-src-op">(</span><span class="py-src-parameter">user</span><span class="py-src-op">)</span><span class="py-src-op">:</span><span class="py-src-newline">
</span><span class="py-src-indent">    </span><span class="py-src-keyword">return</span> <span class="py-src-variable">dbpool</span><span class="py-src-op">.</span><span class="py-src-variable">runQuery</span><span class="py-src-op">(</span><span class="py-src-string">&quot;SELECT age FROM users WHERE name = ?&quot;</span><span class="py-src-op">,</span> <span class="py-src-variable">user</span><span class="py-src-op">)</span><span class="py-src-newline">
</span><span class="py-src-nl">
</span><span class="py-src-dedent"></span><span class="py-src-keyword">def</span> <span class="py-src-identifier">printResult</span><span class="py-src-op">(</span><span class="py-src-parameter">l</span><span class="py-src-op">)</span><span class="py-src-op">:</span><span class="py-src-newline">
</span><span class="py-src-indent">    </span><span class="py-src-keyword">if</span> <span class="py-src-variable">l</span><span class="py-src-op">:</span><span class="py-src-newline">
</span><span class="py-src-indent">        </span><span class="py-src-keyword">print</span> <span class="py-src-variable">l</span><span class="py-src-op">[</span><span class="py-src-number">0</span><span class="py-src-op">]</span><span class="py-src-op">[</span><span class="py-src-number">0</span><span class="py-src-op">]</span><span class="py-src-op">,</span> <span class="py-src-string">&quot;years old&quot;</span><span class="py-src-newline">
</span>    <span class="py-src-dedent"></span><span class="py-src-keyword">else</span><span class="py-src-op">:</span><span class="py-src-newline">
</span><span class="py-src-indent">        </span><span class="py-src-keyword">print</span> <span class="py-src-string">&quot;No such user&quot;</span><span class="py-src-newline">
</span><span class="py-src-nl">
</span><span class="py-src-dedent"></span><span class="py-src-dedent"></span><span class="py-src-variable">getAge</span><span class="py-src-op">(</span><span class="py-src-string">&quot;joe&quot;</span><span class="py-src-op">)</span><span class="py-src-op">.</span><span class="py-src-variable">addCallback</span><span class="py-src-op">(</span><span class="py-src-variable">printResult</span><span class="py-src-op">)</span><span class="py-src-newline">
</span><span class="py-src-endmarker"></span></pre><p>This is straightforward, except perhaps for the return value
    of <code>getAge</code>. It returns a <code class="API"><a href="http://twistedmatrix.com/documents/TwistedDocs/TwistedDocs-1.3.0/api/twisted.internet.defer.Deferred.html" title="twisted.internet.defer.Deferred">twisted.internet.defer.Deferred</a></code>, which allows
    arbitrary callbacks to be called upon completion (or upon
    failure).  More documentation on Deferred is available <a href="defer.html">here</a>.</p><p>In addition to <code>runQuery</code>, there is also <code>runOperation</code>,
    and <code>runInteraction</code> that gets called with a callable (e.g. a function).
    The function will be called in the thread with a <code class="API"><a href="http://twistedmatrix.com/documents/TwistedDocs/TwistedDocs-1.3.0/api/twisted.enterprise.adbapi.Transaction.html" title="twisted.enterprise.adbapi.Transaction">twisted.enterprise.adbapi.Transaction</a></code>,
    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.</p><pre class="python">
<span class="py-src-keyword">def</span> <span class="py-src-identifier">_getAge</span><span class="py-src-op">(</span><span class="py-src-parameter">txn</span><span class="py-src-op">,</span> <span class="py-src-parameter">user</span><span class="py-src-op">)</span><span class="py-src-op">:</span><span class="py-src-newline">
</span>    <span class="py-src-comment"># this will run in a thread, we can use blocking calls
</span><span class="py-src-indent">    </span><span class="py-src-variable">txn</span><span class="py-src-op">.</span><span class="py-src-variable">execute</span><span class="py-src-op">(</span><span class="py-src-string">&quot;SELECT * FROM foo&quot;</span><span class="py-src-op">)</span><span class="py-src-newline">
</span>    <span class="py-src-comment"># ... other cursor commands called on txn ...
</span>    <span class="py-src-variable">txn</span><span class="py-src-op">.</span><span class="py-src-variable">execute</span><span class="py-src-op">(</span><span class="py-src-string">&quot;SELECT age FROM users WHERE name = ?&quot;</span><span class="py-src-op">,</span> <span class="py-src-variable">user</span><span class="py-src-op">)</span><span class="py-src-newline">
</span>    <span class="py-src-variable">result</span> <span class="py-src-op">=</span> <span class="py-src-variable">txn</span><span class="py-src-op">.</span><span class="py-src-variable">fetchall</span><span class="py-src-op">(</span><span class="py-src-op">)</span><span class="py-src-newline">
</span>    <span class="py-src-keyword">if</span> <span class="py-src-variable">result</span><span class="py-src-op">:</span><span class="py-src-newline">
</span><span class="py-src-indent">        </span><span class="py-src-keyword">return</span> <span class="py-src-variable">result</span><span class="py-src-op">[</span><span class="py-src-number">0</span><span class="py-src-op">]</span><span class="py-src-op">[</span><span class="py-src-number">0</span><span class="py-src-op">]</span><span class="py-src-newline">
</span>    <span class="py-src-dedent"></span><span class="py-src-keyword">else</span><span class="py-src-op">:</span><span class="py-src-newline">
</span><span class="py-src-indent">        </span><span class="py-src-keyword">return</span> <span class="py-src-variable">None</span><span class="py-src-newline">
</span><span class="py-src-nl">
</span><span class="py-src-dedent"></span><span class="py-src-dedent"></span><span class="py-src-keyword">def</span> <span class="py-src-identifier">getAge</span><span class="py-src-op">(</span><span class="py-src-parameter">user</span><span class="py-src-op">)</span><span class="py-src-op">:</span><span class="py-src-newline">
</span><span class="py-src-indent">    </span><span class="py-src-keyword">return</span> <span class="py-src-variable">dbpool</span><span class="py-src-op">.</span><span class="py-src-variable">runInteraction</span><span class="py-src-op">(</span><span class="py-src-variable">_getAge</span><span class="py-src-op">,</span> <span class="py-src-variable">user</span><span class="py-src-op">)</span><span class="py-src-newline">
</span><span class="py-src-nl">
</span><span class="py-src-dedent"></span><span class="py-src-keyword">def</span> <span class="py-src-identifier">printResult</span><span class="py-src-op">(</span><span class="py-src-parameter">age</span><span class="py-src-op">)</span><span class="py-src-op">:</span><span class="py-src-newline">
</span><span class="py-src-indent">    </span><span class="py-src-keyword">if</span> <span class="py-src-variable">age</span> <span class="py-src-op">!=</span> <span class="py-src-variable">None</span><span class="py-src-op">:</span><span class="py-src-newline">
</span><span class="py-src-indent">        </span><span class="py-src-keyword">print</span> <span class="py-src-variable">age</span><span class="py-src-op">,</span> <span class="py-src-string">&quot;years old&quot;</span><span class="py-src-newline">
</span>    <span class="py-src-dedent"></span><span class="py-src-keyword">else</span><span class="py-src-op">:</span><span class="py-src-newline">
</span><span class="py-src-indent">        </span><span class="py-src-keyword">print</span> <span class="py-src-string">&quot;No such user&quot;</span><span class="py-src-newline">
</span><span class="py-src-nl">
</span><span class="py-src-dedent"></span><span class="py-src-dedent"></span><span class="py-src-variable">getAge</span><span class="py-src-op">(</span><span class="py-src-string">&quot;joe&quot;</span><span class="py-src-op">)</span><span class="py-src-op">.</span><span class="py-src-variable">addCallback</span><span class="py-src-op">(</span><span class="py-src-variable">printResult</span><span class="py-src-op">)</span><span class="py-src-newline">
</span><span class="py-src-endmarker"></span></pre><p>Also worth noting is that these examples assumes that dbmodule
    uses the <q>qmarks</q> 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 -- <code class="python">runQuery(query,
    params, ...)</code> maps directly onto <code class="python">cursor.execute(query, params, ...)</code>.</p><h2>And that's it!<a name="auto4"></a></h2><p>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.</p></div><p><a href="../howto/index.html">Index</a></p><span class="version">Version: 1.3.0</span></body></html>