4

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

该函数将在线程中使用 twisted.enterprise.adbapi.Transaction 调用,它基本上模仿了 DB-API 游标。在所有情况下,数据库事务将在您的数据库使用完成后提交,除非引发异常,在这种情况下它将回滚。

这并不像我想要的那样精确。我的“数据库使用完成”到底是什么时候?是在调用处理程序的 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() 的方法完成而没有抛出异常时,事务就被提交了。如果是这样的话,我想我必须把所有东西,包括对 web 服务器的调用同步放在 saveStuffToDatabase() 中?

4

1 回答 1

1

好吧,我使用同步调用重新实现了代码,它看起来确实可以正常工作。查看 runInteraction() 方法的文档,它变得更加清晰:

def runInteraction(self, 交互, *args, **kw):

与数据库交互并返回结果。“交互”是一个可调用对象,它将在使用池连接的线程中执行。它将作为参数传递一个 Transaction 对象(其接口与您选择的 DB-API 模块的数据库游标的接口相同),其结果将作为 Deferred 返回。如果运行该方法引发异常,则事务将回滚。如果该方法返回一个值,则事务将被提交。

于 2012-10-03T16:12:27.537 回答