简体   繁体   中英

Transaction in non-blocking client?

We are using momoko and having following standard setup for async connection to db in tornado application:

class BaseHandler(tornado.web.RequestHandler):
    @property
    def db(self):
        # Create a database connection when a request handler is called
        # and store the connection in the application object.
        if not hasattr(self.application, 'db'):
            self.application.db = momoko.AsyncClient({
                'host': 'localhost',
                'database': 'momoko',
                'user': 'frank',
                'password': '',
                'min_conn': 1,
                'max_conn': 20,
                'cleanup_timeout': 10
            })
        return self.application.db

One day, I found that code like this, will block application:

fail = yield gen.Task(self.db.execute, 'BEGIN; SELECT * FROM non_existing_table; END;')

First idea, that come in head, was:

try:
    fail = yield gen.Task(self.db.execute, 'BEGIN; SELECT * FROM non_existing_table; END;')
except:
    reconnect()

After some digging on subject, I found that it's better to do something like this:

try:
    fail = yield gen.Task(self.db.execute, 'BEGIN; SELECT * FROM non_existing_table; END;')
except:
    yield gen.Task(self.db.execute, 'ROLLBACK;')

And finally, after exploring source code of momoko I found, that it's better to use blocking client for transaction.

So BaseHandler transformed into:

class BaseHandler(tornado.web.RequestHandler):
    @property
    def db(self):
        # Create a database connection when a request handler is called
        # and store the connection in the application object.
        if not hasattr(self.application, 'db'):
            self.application.db = momoko.AsyncClient({
                'host': 'localhost',
                'database': 'momoko',
                'user': 'frank',
                'password': '',
                'min_conn': 1,
                'max_conn': 20,
                'cleanup_timeout': 10
            })
        return self.application.db

    @property
    def bdb(self):
        # Create a database connection when a request handler is called
        # and store the connection in the application object.
        if not hasattr(self.application, 'bdb'):
            self.application.bdb = momoko.BlockingClient({
                'host': 'localhost',
                'database': 'momoko',
                'user': 'frank',
                'password': '',
                'min_conn': 1,
                'max_conn': 20,
                'cleanup_timeout': 10
            })
        return self.application.bdb

Now my question... is there any safe way to use transaction in AsyncClient ? Or AsyncClient is commonly used for read from database, not for writing/updating data there?

I'm working on Momoko 1.0.0 and I just released the first beta. Transactions are one of the new features. Here's my post on the mailinglist: https://groups.google.com/forum/?fromgroups=#!topic/python-tornado/7TpxBQvbHZM

Versions before 1.0.0 don't support transactions, because everytime you run execute there's a possibility that AsyncClient will pick a new connection for you and you won't be able to rollback your transaction if anything goes wrong.

I hope this helps a bit. :)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM