联系
Knight's Tale » 技术

peewee的 @db.commit_on_success 事务 坑

2014-11-30 01:56

最近使用python的ORM peewee,踩了一个大坑

@db.commit_on_success 是一个注解式写法,加了此注解的函数会被“切面”。对于一般函数来说,work perfect. 但是,如果把此 方法 加在 action(controller)上面呢,会发生什么事情呢?

在这种情况下,

  • 1):如果你的db是不断长连接的(没有池),那没啥问题。因为所有请求均是使用同一个数据库连接。
  • 2):如果你采用了池化DB连接技术,每次用户请求都会在池中寻找可用连接,每次请求结束都会close掉此连接(PEEWEE最佳实践)。这样,就会先执行释放DB连接,然后再执行 commit 函数。这个顺序理论就是不对的,正确的做法是 先执行 commit 函数后,再来释放DB连接。但是在某些情况下,这个顺序又是对的。这就增加了很多迷惑性。这里加以解释一下:试考虑以下情景:
    • A:请求后,将连接放回池中。commit_on_success在执行时,发现没有连接了,尝试从池中获取连接。此时刚好拿到同一个连接。
    • B:请求后,将连接放回池中。commit_on_success在执行时,发现没有连接了,尝试从池中获取连接。此时不巧,拿到另一个连接。

A情况下,没有问题。同一个连接执行事务,perfect. B情况下,两个不同的连接,无法执行事务!并且,peewee这里没有异常发生!但是实际上,commit没有执行。数据没写到数据库里。

因此,就发现了诧异的事情,有时候写到数据库,有时候没写到数据库。。在数据库繁忙的时候,大概率事件无法写到数据库,在数据库清闲时,小概率事件没办法写到数据库中。

若有若无,这是最难排查的问题。

没有异常,代表着我们以为数据写到数据库里,但实际上没有。。。所以是个坑。

因此,结论是,不管是java spring中的事务,还是peewee的commit_on_success事务,均不以放在action(controller)上。