transactions - 扭曲的 adbapi 事务何时真正提交?

标签 transactions twisted cyclone

我在旋风网络服务器中使用 adbapi。首先,我的处理程序将一些内容写入 SQL 数据库,然后向另一个 Web 服务器发出 HTTP 请求。如果该 HTTP 请求失败,我希望数据库事务回滚。但是,我没有得到那种效果。查看文档,它说

The function will be called in the thread with a twisted.enterprise.adbapi.Transaction, 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.



这并不像我想要的那样精确。我的“数据库使用完成”究竟是在什么时候?那是在调用处理程序的 self.finish() 方法时吗?传入 ConnectionPool.runInteraction() 的方法什么时候完成?

这是我的代码
class AccountCreationHandler(BaseRequestHandler):
    @cyclone.web.asynchronous
    def post(self, accessKey, *args, **kwargs):
        try:    
            d = connPool.runInteraction(self.saveStuffToDatabase)
            d.addCallback(self.callWebServer)
            d.addCallback(self.formatResult)
            d.addErrback(self.handleFailure)

        except Exception, e:
            self.handleException(e)


    def saveStuffToDatabase(self, txn):
        txn.execute("INSERT INTO Table1 (f1) VALUES ('v1')")


    def callWebServer(self):
        agent = Agent(reactor)
        hdrs = Headers({ "Content-type": ["application/json"] })
        values = json.dumps({ "someField": 123 })
        body = SimpleProducer(values)
        url = "http://somewebserver.com"
        d = agent.request("POST", url, hdrs, body)
        d.addCallback(self.handleWebResponse)
        return d


    def handleWebResponse(self, response):
        if response.code == 200:
            d = Deferred()
            receiver = SimpleReceiver(d)
            response.deliverBody(receiver)
            d.addCallback(self.saveWebServerResults)
            return d
        else:
            raise Exception("web server failed with http status code %d" % response.code)


    def saveWebServerResults(self, body):
        self.results = body


    def formatResult(self):    
        self.finish(self.results)


class SimpleProducer(object):
    implements(IBodyProducer)

    def __init__(self, body):
        self.body = body
        self.length = len(body)

    def startProducing(self, consumer):
        consumer.write(self.body)
        return succeed(None)

    def pauseProducing(self):
        pass

    def stopProducing(self):
        pass


class SimpleReceiver(Protocol):
    def __init__(self, d):
        self.buf = ''
        self.d = d

    def dataReceived(self, data):
        self.buf += data

    def connectionLost(self, reason):
        if type(reason.value) == ResponseDone:
            self.d.callback(self.buf)
        else:
            self.d.errback(reason)

在 Web 服务器抛出错误或与它的连接超时的情况下,或者基本上如果代码通过 saveStuffToDatabase 方法,则在发生错误时不会回滚任何内容。

我猜这意味着当传递给 ConnectionPool.runInteraction() 的方法完成而没有抛出异常时,事务就被提交了。如果是这种情况,我想那么我就必须把所有内容都放在 saveStuffToDatabase() 中,包括同步调用 Web 服务器?

最佳答案

好吧,我使用同步调用重新实现了代码,它似乎可以正常工作。查看 runInteraction() 方法的文档,它更清楚一点:

def runInteraction(self, interaction, *args, **kw):

Interact with the database and return the result. The 'interaction' is a callable object which will be executed in a thread using a pooled connection. It will be passed an Transaction object as an argument (whose interface is identical to that of the database cursor for your DB-API module of choice), and its results will be returned as a Deferred. If running the method raises an exception, the transaction will be rolled back. If the method returns a value, the transaction will be committed.

关于transactions - 扭曲的 adbapi 事务何时真正提交?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12592481/

相关文章:

ruby-on-rails - 如何在 ActiveRecord 事务中获得保存(无感叹号)语义?

transactions - IPN 返回不同的交易 ID

python - twisted的Deferred是如何实现的?

python - 如何从扭曲的 inlineCallbacks 修饰函数中捕获异常?

python - Twisted、Cyclone 或Tornado 是否可以开箱即用地实现SMP 多核

python - 防止 cyclone 评估 Handlebar 的模板

memory-leaks - 使用 Twisted + Cyclone + PyPy 处理 POST 请求会导致内存泄漏?

unit-testing - 带有 SQLite 内存数据库和 NHibernate 的 TransactionScope

python - 监控文件扭曲

java - Spring 事务管理不适用于 Spring Boot + MyBatis?