ZODB with Tornado

I have a small web application built using Tornado where I would like to use ZODB for some data storage. According to ZODB docs, multithreaded programs are supported , but they should start a new connection for the stream . I think it means I have to do something like

### On startup dbFilename = os.path.join(os.path.dirname(os.path.abspath(__file__)), "Data.fs") db = DB(FileStorage(dbFilename)) ### Example handler class Example(tornado.web.RequestHandler): def get(self): try: conn = db.open() root = conn.root() ### do stuff with root here root._p_changed = 1 ## Include these lines for writes transaction.commit() ## on sub-elements finally: conn.close() 

First, is a new connection still necessary for all db-interacting handlers, or just those who write? Would it be wise to start one connection at startup and use it for all my readings, and then perform the above connection with songs and dances only when I need to write something?

Secondly, what is the idiomatic way of abstracting this pattern in Python? I have something like

 def withDB(fn): try: conn = db.open() root = conn.root() res = fn(root) root._p_changed = 1 transaction.commit() return res finally: conn.close() def delete(formName): def local(root): ### do stuff with root here return withDB(local) 

but maybe my lisp shows.

A general approach check would also be welcome.

+4
source share
1 answer

You need to create a new connection for each thread. ZODB provides each connection with a sequential view of transactions (MVCC, multi-view concurrency), so even for reading you need a separate connection. A connection can be reused for consecutive requests in a single thread.

So, for the connection, I would use the pool for the stream provided by ZODB.DB , possibly caching the connection for each request (as pyramid_zodbconn does).

Inside 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 will be launched upon entry and transferred upon exit without exception, aborted upon exit with exception.

You can also create a context manager to handle the ZODB connection:

 from contextlib import contextmanager @contextmanager def zodbconn(db): conn = db.open() yield conn.root() conn.close() 

then use this as a context manager along with a 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 accepts the database object and returns the root object, automatically closing the connection when the context terminates again.

+4
source

All Articles