求助: TorMySQL 忽略异常

2016-10-04 21:42:46 +08:00
 bwangel

今天在用 TorMySQL 的时候遇到了一个问题,就是无法忽略表不存在的异常:

问题描述

我的代码如下:

class Application(tornado.web.Application):
    def __init__(self):
        handlers = [
            (r"/join", RegisterHandler),
            (r"/", MainHandler),
            (r"/websocket", EchoWebSocket),
        ]
        settings = dict(
            cookie_secret="__TODO:_GENERATE_YOUR_OWN_RANDOM_VALUE_HERE_",
            template_path=os.path.join(os.path.dirname(__file__), "templates"),
            static_path=os.path.join(os.path.dirname(__file__), "static"),
            xsrf_cookie=True,
            debug=True,
            schema=os.path.join(os.path.dirname(__file__), "schema.sql"),
        )
        self.pool = tormysql.ConnectionPool(
            max_connections = 20,
            idle_seconds = 7200,
            wait_connection_timeout = 3,
            host = "127.0.0.1",
            user = "chat",
            password = "chat",
            db = "chat",
            charset = "utf8"
        )
        super(Application, self).__init__(handlers, **settings)
        self.may_create_db()

    @gen.coroutine
    def may_create_db(self):
        with (yield self.pool.Connection()) as conn:
            try:
                with conn.cursor() as cursor:
                    yield cursor.execute("SELECT * FROM user")
            except pymysql.err.ProgrammingError as e:
                logging.error(e)
                subprocess.Popen(['mysql',
                                '--host={}'.format('127.0.0.1'),
                                '--database={}'.format('chat'),
                                '--user={}'.format('chat'),
                                '--password={}'.format('chat')],
                                stdin=open(self.settings['schema']))
            except:
                yield conn.rollback()
            else:
                yield conn.commit()
        yield self.pool.close()

may_create_db函数中,我会尝试去连接数据库,如果对应的表不存在的话,那么就会创建相关的表,但现在运行的时候遇到了一点问题,就是那个pymysql.err.ProgrammingError 还是会显示出来。

运行结果如下:

➜ /home/yundongx/gitroom/chat (dev) ✗ [chat]$ python app.py
2016-10-04 21:27:10,677 INFO: Server starts on port 8888
2016-10-04 21:27:10,704 ERROR: (1146, "Table 'chat.user' doesn't exist")
mysql: [Warning] Using a password on the command line interface can be insecure.
2016-10-04 21:27:10,710 ERROR: Future <tornado.concurrent.Future object at 0x7f39862ca2e8> exception was never retrieved: Traceback (most recent call last):
  File "/home/yundongx/.virtualenvs/chat/lib/python3.5/site-packages/tornado/gen.py", line 1021, in run
    yielded = self.gen.throw(*exc_info)
  File "app.py", line 94, in may_create_db
    yield cursor.execute("SELECT * FROM test")
  File "/home/yundongx/.virtualenvs/chat/lib/python3.5/site-packages/tornado/gen.py", line 1015, in run
    value = future.result()
  File "/home/yundongx/.virtualenvs/chat/lib/python3.5/site-packages/tornado/concurrent.py", line 237, in result
    raise_exc_info(self._exc_info)
  File "<string>", line 3, in raise_exc_info
  File "/home/yundongx/.virtualenvs/chat/lib/python3.5/site-packages/tormysql/util.py", line 14, in finish
    result = fun(*args, **kwargs)
  File "/home/yundongx/.virtualenvs/chat/lib/python3.5/site-packages/pymysql/cursors.py", line 166, in execute
    result = self._query(query)
  File "/home/yundongx/.virtualenvs/chat/lib/python3.5/site-packages/pymysql/cursors.py", line 322, in _query
    conn.query(q)
  File "/home/yundongx/.virtualenvs/chat/lib/python3.5/site-packages/pymysql/connections.py", line 835, in query
    self._affected_rows = self._read_query_result(unbuffered=unbuffered)
  File "/home/yundongx/.virtualenvs/chat/lib/python3.5/site-packages/pymysql/connections.py", line 1019, in _read_query_result
    result.read()
  File "/home/yundongx/.virtualenvs/chat/lib/python3.5/site-packages/pymysql/connections.py", line 1302, in read
    first_packet = self.connection._read_packet()
  File "/home/yundongx/.virtualenvs/chat/lib/python3.5/site-packages/pymysql/connections.py", line 981, in _read_packet
    packet.check_error()
  File "/home/yundongx/.virtualenvs/chat/lib/python3.5/site-packages/pymysql/connections.py", line 393, in check_error
    err.raise_mysql_exception(self._data)
  File "/home/yundongx/.virtualenvs/chat/lib/python3.5/site-packages/pymysql/err.py", line 107, in raise_mysql_exception
    raise errorclass(errno, errval)
pymysql.err.ProgrammingError: (1146, "Table 'chat.test' doesn't exist")

我的疑问

  1. 我调用may_create_db 的方式是否正确?
  2. 我了解到那个异常显示的原因是因为相关Future的异常没有被取出,所以自动加到了logging里面,打印了出来,如何才能让那个异常不显示出来呢?
1966 次点击
所在节点    问与答
12 条回复
bwangel
2016-10-04 21:47:41 +08:00
@sujin190 , Please help me!
bwangel
2016-10-04 22:07:21 +08:00
好吧,脑子犯迷糊了,调用方式铁定有问题啊!

应该这么调用:

```
def main():
tornado.options.parse_command_line()
app = Application()
http_server = tornado.httpserver.HTTPServer(app)
http_server.listen(options.port)
logging.info("Server starts on port {}".format(options.port))
ioloop = tornado.ioloop.IOLoop.current()
ioloop.run_sync(app.may_create_db)
ioloop.start()


if __name__ == "__main__":
main()
```
bwangel
2016-10-04 22:11:23 +08:00
错误是在 _TracebackLogger 里面抛出来的。

http://www.tornadoweb.org/en/stable/_modules/tornado/concurrent.html

它的 docstring 里面就说了

However, we don't want to log the exception as soon as
set_exception() is called: if the calling code is written
properly, it will get the exception and handle it properly. But
we *do* want to log it if result() or exception() was never called

它只会记录 result() 或者 exception() 没有被调用的异常,我就想估计是调用方式出错了,好吧,真的是。
sujin190
2016-10-06 21:28:10 +08:00
@bwangel 放假回家了,没网,不好意思
似乎不是这个问题啊,从日志上看你那个 try 是生效了,不应该再出现后面的错误才,回去后我调试下看看是否还有其他的问题吧
bwangel
2016-10-07 21:37:47 +08:00
@sujin190 ,已经解决了。

我感觉我那样的调用方式好像不太对,我个人理解是这样的:

我是在 app 的构造函数里面直接调用 may_create_db 这个函数的,此时 ioloop 还没有生成,此时那个查询语句的跑出异常了,但是还不能进行相应触发(因为没有 ioloop ),也就意味着不能调用相应 Future 的 set_exception 函数。所以这个异常就会被放到_TracebackLogger 里面,重新输出一遍。


还有一个问题想请教一下,请问一下如果我写了一个查询函数,类似于

@gen.coroutine
def select():
利用 tormysql 做一些查询

这个查询函数能够直接被调用吗?还是必须要放到 ioloop.run_sync 中调用,或者放到另外一个 coroutine 中通过 yield 调用。
sujin190
2016-10-07 21:43:51 +08:00
@bwangel 但我觉得不是这个问题,能贴一下完整代码么? ioloop 是自动生成的, start 只是驱动其运行而已
bwangel
2016-10-07 21:52:39 +08:00
bwangel
2016-10-07 21:53:53 +08:00
项目仓库就是这个 Chat ,写的一个很简单的 Demo 项目。
bwangel
2016-10-07 21:57:55 +08:00
sujin190
2016-10-08 12:54:40 +08:00
@bwangel 我测试了下你给的代码,没有你说的这个问题啊。。
bwangel
2016-10-09 14:19:37 +08:00
@sujin190 ,我又新建文件尝试重现这个错误,确实没有了。。好诡异啊!
sujin190
2016-10-09 21:35:03 +08:00
@bwangel 。。

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/310577

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX