今天在用 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")
may_create_db
的方式是否正确? 2
bwangel OP 好吧,脑子犯迷糊了,调用方式铁定有问题啊!
应该这么调用: ``` 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() ``` |
3
bwangel OP 错误是在 _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() 没有被调用的异常,我就想估计是调用方式出错了,好吧,真的是。 |
4
sujin190 2016-10-06 21:28:10 +08:00
@bwangel 放假回家了,没网,不好意思
似乎不是这个问题啊,从日志上看你那个 try 是生效了,不应该再出现后面的错误才,回去后我调试下看看是否还有其他的问题吧 |
5
bwangel OP @sujin190 ,已经解决了。
我感觉我那样的调用方式好像不太对,我个人理解是这样的: 我是在 app 的构造函数里面直接调用 may_create_db 这个函数的,此时 ioloop 还没有生成,此时那个查询语句的跑出异常了,但是还不能进行相应触发(因为没有 ioloop ),也就意味着不能调用相应 Future 的 set_exception 函数。所以这个异常就会被放到_TracebackLogger 里面,重新输出一遍。 还有一个问题想请教一下,请问一下如果我写了一个查询函数,类似于 @gen.coroutine def select(): 利用 tormysql 做一些查询 这个查询函数能够直接被调用吗?还是必须要放到 ioloop.run_sync 中调用,或者放到另外一个 coroutine 中通过 yield 调用。 |
7
bwangel OP |
8
bwangel OP 项目仓库就是这个 Chat ,写的一个很简单的 Demo 项目。
|
9
bwangel OP |