您好,欢迎访问一九零五行业门户网

在Twisted下用MySQL adbapi获取自增id

d jango的orm有一个很便捷的功能,其实也应该说是一个很基本的功能吧。就是在对一个model调用 save() 插入到数据库后,会将创建的
d jango的orm有一个很便捷的功能,其实也应该说是一个很基本的功能吧。就是在对一个model调用 save() 插入到数据库后,会将创建的自增id同步到当前model上。sql中调用 insert 默认的返回值是插入的行数,就目前的应用来说,其实是一个没啥意义的返回值,所以django的orm能够处理好自增id的同步是一件很让人愉悦的事。
不过没有使用django,最近用的是twisted提供的adbapi,如何获取自增id呢?
如果是我力挺的postgresql的话,很简单,,给 insert 加上 returning 语句就可以了:
insert into distributors (did, dname)
values (default, 'xyz widgets') returning did;
不过mysql呢?
最近用了一阵子mysql,只是从命令行自动补全这方面来说,就已经明显地感觉到和postgresql的差距了。老实说真不知道为啥那么多人如此热爱深爱着mysql……
在stackoverflow上搜了一下,找到两种方法,要么是使用
select last_insert_id();
或者是使用connector的 mysql_insert_id() 函数,这个对于python中的 mysqldb 来说就是connection的 insert_id() 函数,比如:
conn = mysqldb.connect(host='heaven', user='god',
                       passwd='jesus', db='elysium')
cursor = conn.cursor()
cursor.execute('insert into account values (%s, %s)',
               ('satan', 'male or female, who knows'))
new_id = conn.insert_id() # 过程也还算简单,但是对于twisted的adbapi来说,我们的活并没有结束。为啥呢?因为adbapi用的是线程池来管理mysql的连接的,每次query调用,都会从线程池中获取一个线程,然后将相应的事务defer到该线程来处理。其默认的事务是以单个sql语句为划分的,所以说,对于mysql这样在执行完后还需要做其他操作的需求来说,默认的接口是无法满足的。这儿我再吐一下槽,还是pg好啊……
默认接口不够用,那我们就只能扩展它了。稍稍看一下adbapi的源代码我们可以发现,对于通常事务,adbapi其实是使用了 runinteraction 这个接口函数的。具体不同的事务,adbapi是将相应的callback作为其第一个参数,然后在 defertothreadpool 时指定线程运行该callback来实现。所以,我们只需要为mysql定义一种新的事务就可以了。
下面就是我们需要定义的新事务:
def runmysqlinsert(self, *args, **kw):
    assert self.dbapiname == 'mysqldb'
    return self.runinteraction(self._runmysqlinsert, *args, **kw)
def _runmysqlinsert(self, trans, *args, **kw):
    trans.execute(*args, **kw)
    return trans.connection.insert_id()
ok,接下来,把这两个函数monkey patch到adbapi上就完事了:)
其它类似信息

推荐信息