2013-04-09 3 views
4

У меня есть небольшое веб-приложение, построенное с помощью Tornado, где я бы хотел использовать ZODB для некоторого хранения данных. Согласно документам ZODB, multi-threaded programs are supported, but they should start up a new connection per thread. Я думаю, что означает, что я должен сделать что-то вродеZODB с Tornado

### 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() 

Во-первых, это новое соединение по-прежнему необходимо для всех дб взаимодействующих обработчиков или только те, которые пишет делать? Было бы разумно начать одно соединение при запуске и использовать его для всех моих чтений, а затем выполнить вышеупомянутое соединение с песнями и танцами только тогда, когда мне нужно что-то написать?

Во-вторых, что такое идиоматический способ абстрагирования этого шаблона в Python? У меня есть что-то вроде

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) 

в виду, но это, вероятно, мой показ Лиспа.

Общепринятая проверка на подходе также будет приветствоваться.

ответ

4

Вам необходимо создать новое соединение на поток. ZODB обеспечивает каждое соединение с последовательным представлением каждой транзакции (MVCC, управление просмотром нескольких просмотров), поэтому даже для чтения вам требуется отдельное соединение. Соединение может быть повторно использовано для последовательных запросов в одном потоке.

Итак, для подключения я использовал бы пул потоков, предоставленный ZODB.DB, возможно, кеширование соединения для каждого запроса (как это делает pyramid_zodbconn).

В обработчиков запросов, вы можете использовать менеджер транзакций как менеджеру контекста:

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 

Используя transaction.manager объект как менеджер контекста гарантирует, что транзакция начинается на въезд, и совершил на выходе без исключения , прерывается с выходом с исключением.

Вы можете создать менеджер контекста для обработки соединения ZODB, а также:

from contextlib import contextmanager 

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

затем использовать его в качестве контекста менеджера вместе с менеджером транзакций:

class Example(tornado.web.RequestHandler): 
    def get(self): 
     with zodbconn(db) as root, transaction.manager: 
      res = fn(root) 
      root._p_changed = 1 

Этот контекст менеджер принимает объекта базы данных и возвращает корневой объект, автоматически закрывая соединение при повторном завершении контекста.

+0

Хм. Согласно [this] (http://zodb.readthedocs.org/en/latest/api.html#connection-pool), 'ZODB.DB' уже выполняет объединение пулов через' open() '. Означает ли это, что вы можете сделать что-то вроде 'with transaction.manager как m: db.open (transaction_manager = m) ...'? – Inaimathi

+0

А, конечно, так оно и есть; Я испорчен системами, которые автоматически обрабатывают соединение и транзакции. :-) –

Смежные вопросы