什么时候扭曲的adbapi交易真的被提交了?

时间:2012-09-25 23:20:16

标签: transactions twisted cyclone

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

  

该函数将在带有a的线程中调用   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()的方法完成而没有抛出异常时,事务就会被提交。如果是这种情况,我想我必须把所有内容,包括在saveStuffToDatabase()中同步调用Web服务器?

1 个答案:

答案 0 :(得分:1)

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

  

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

     

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