You need to create a new connection per thread. The ZODB provides each connection with a consistent per-transaction view (MVCC, multi-view concurrency control), so even for reading you want a separate connection. The connection can be re-used for sequential requests in one thread.
So for the connection, I'd use the per-thread pool supplied by ZODB.DB
, perhaps caching the connection per request (as pyramid_zodbconn does).
Within your request handlers, you can use the transaction manager as a context manager:
class Example(tornado.web.RequestHandler):
def get(self):
connection = some_connection_pool.get_connection()
with transaction.manager:
root = conn.root()
res = fn(root)
root._p_changed = 1
Using the transaction.manager
object as a context manager ensures that the transaction is started on enter, and committed on exit without exception, aborted on exit with an exception.
You could create a context manager to handle the ZODB connection as well:
from contextlib import contextmanager
@contextmanager
def zodbconn(db):
conn = db.open()
yield conn.root()
conn.close()
then use that as a context manager together with the transaction manager:
class Example(tornado.web.RequestHandler):
def get(self):
with zodbconn(db) as root, transaction.manager:
res = fn(root)
root._p_changed = 1
This context manager takes the database object, and returns the root object, closing the connection automatically when the context is exited again.