python TorMySQL 异常处理不显示traceback的坑

背景:

最近找到一个异步数据库驱动,TorMySQL,ab测试后效果是其他几个异步驱动最好的,遂用之。

因为尽可能业务逻辑层和数据访问层分离,并且考虑到单一负责原则,把每一个数据库的操作简称为service,如user_service,work_service之类的。

很多情况下,每一个逻辑业务都是要N个service合作才完成的。

所以就不在单个service中try except,而是在业务逻辑层中try except。

一是:

少写很多代码,不然每一个service都要try except之后,logging.error(ex, exc_info=1)打印traceback,然后再raise ex,多麻烦...

二是:

考虑到很多情况下有用到事务,只能在业务逻辑层捕获exception,捕获到就conn.rollback(),没捕获到就conn.commit()。


然而,我上面这种设计竟然没捕获到traceback,简直匪夷所思。

好了,背景交代完毕。


版本:

python 2.7
tormysql==0.2.9
tornado==4.2


测试1:

import logging

from tornado.ioloop import IOLoop
from tornado import gen
import tormysql

pool = tormysql.ConnectionPool(
    max_connections = 20, #max open connections
    idle_seconds = 7200, #conntion idle timeout time, 0 is not timeout
    wait_connection_timeout = 3, #wait connection timeout
    host = "127.0.0.1",
    user = "root",
    passwd = "123qwe",
    db = "chanzai_dev",
    charset = "utf8"
)

@gen.coroutine
def aa(conn):
        sql = "SELECT * FROM UserDevice where user_id = %s" % 100002
        with conn.cursor() as cursor:
            yield cursor.execute(sql)
            cursor.fetchone()
            # 下面是故意出错代码
            a = '10'
            b = a / 10
            print b
@gen.coroutine
def bb(conn):
    yield aa(conn)

@gen.coroutine
def cc():
    with (yield pool.Connection()) as conn:
        try:
            yield bb(conn)
        except KeyError:
            pass
        except Exception, ex:
            yield conn.rollback()
            logging.error(ex, exc_info=1)

ioloop = IOLoop.instance()
ioloop.run_sync(cc)
测试结果:

G:\projects\myApp\tmp>a.py
ERROR:root:unsupported operand type(s) for /: 'str' and 'int'
None


测试2:

import logging

from tornado.ioloop import IOLoop
from tornado import gen
import tormysql

pool = tormysql.ConnectionPool(
    max_connections = 20, #max open connections
    idle_seconds = 7200, #conntion idle timeout time, 0 is not timeout
    wait_connection_timeout = 3, #wait connection timeout
    host = "127.0.0.1",
    user = "root",
    passwd = "123qwe",
    db = "chanzai_dev",
    charset = "utf8"
)

@gen.coroutine
def aa(conn):
        sql = "SELECT * FROM UserDevice where user_id = %s" % 100002
        with conn.cursor() as cursor:
            yield cursor.execute(sql)
            cursor.fetchone()
            # 下面是故意出错代码
            a = '10'
            b = a / 10
            print b
@gen.coroutine
def bb(conn):
    yield aa(conn)

@gen.coroutine
def cc():
    with (yield pool.Connection()) as conn:
        try:
            yield bb(conn)
        except KeyError:
            pass
        except Exception, ex:
            logging.error(ex, exc_info=1)
            yield conn.rollback()

ioloop = IOLoop.instance()
ioloop.run_sync(cc)
测试结果:
G:\projects\myApp\tmp>a.py
ERROR:root:unsupported operand type(s) for /: 'str' and 'int'
Traceback (most recent call last):
  File "G:\projects\myApp\tmp\a.py", line 40, in cc
    yield bb(conn)
  File "G:\Python27\lib\site-packages\tornado\gen.py", line 1015, in run
    value = future.result()
  File "G:\Python27\lib\site-packages\tornado\concurrent.py", line 237, in result
    raise_exc_info(self._exc_info)
  File "G:\Python27\lib\site-packages\tornado\gen.py", line 1021, in run
    yielded = self.gen.throw(*exc_info)
  File "G:\projects\myApp\tmp\a.py", line 34, in bb
    yield aa(conn)
  File "G:\Python27\lib\site-packages\tornado\gen.py", line 1015, in run
    value = future.result()
  File "G:\Python27\lib\site-packages\tornado\concurrent.py", line 237, in result
    raise_exc_info(self._exc_info)
  File "G:\Python27\lib\site-packages\tornado\gen.py", line 1024, in run
    yielded = self.gen.send(value)
  File "G:\projects\myApp\tmp\a.py", line 30, in aa
    b = a / 10
TypeError: unsupported operand type(s) for /: 'str' and 'int'

G:\projects\myApp\tmp>


观察结果:

根据两个测试,其实只改了一个地方,就是:
        except Exception, ex:
            logging.error(ex, exc_info=1)
            yield conn.rollback()
        except Exception, ex:
            yield conn.rollback()
            logging.error(ex, exc_info=1)
前者才能得到想要的结果,为什么有后者这种写法呢,是因为,想着对于数据库的操作出错了还是尽早rollback为好,没想到就踩了坑。



原因分析:

看了下pymysql的connections.py源码(因为TorMySQL是对pymysql的封装),发现确实有很多try except,我都不用具体往下看了,因为很大可能性是我们的ex被pymysql给捕获到了,但是raise出来的是pymysql处理过的ex,所以看不到traceback...吧
解决方案就是先logging.error(ex, exc_info=1) 再 yield conn.rollback()



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值