【问题标题】:PyMySql query in async function异步函数中的 PyMySql 查询
【发布时间】:2017-11-20 17:15:03
【问题描述】:

我正在使用tornado 框架来编写一个非阻塞API。

我想进行异步 mysql 查询,为此我应该使用异步 mysql 库(用于龙卷风)还是可以使用类似的东西?

import tornado.web
import pymysql
import json


class AsyncDBCalls(tornado.web.RequestHandler):
    def initialize(self):
        database = {
            "host": "localhost",
            "user": "root",
            "password": "123456",
            "db": "tableName",
            "cursorclass": pymysql.cursors.DictCursor,
            "autocommit": True,
            "charset": "utf8"
        }
        try:
            self.db_connection = pymysql.connect(**database)
            self.db = self.db_connection.cursor()
        except pymysql.err.OperationalError:
            pass
            # TODO logging

    async def make_query(self, query):
        self.db.execute(query)
        results = self.db.fetchall()
        return results

    @tornado.web.asynchronous
    async def get(self):
        query = "SELECT * FROM users"
        results = await self.make_query(query)
        self.set_status(200)
        self.add_header("Content-Type", "text/json")
        self.write(json.dumps(results))
        self.finish()

这个 make_query 函数是异步运行的吗?这段代码可以用于非阻塞API吗?

【问题讨论】:

  • 不,PyMySQL 不是异步的。因此,它会阻止 Tornado 服务器。但是你可以使用aiomysql。它基于PyMySQL,因此您不必学习很多东西。

标签: python mysql asynchronous tornado pymysql


【解决方案1】:

请改用TorMySQL

您还应该考虑使用连接池,因为您必须使用多个连接:

self.pool = tormysql.ConnectionPool(
        max_connections=256,
        wait_connection_timeout=5,
        idle_seconds=7200,
        host=<host>,
        db=<database>,
        user=<user>,
        passwd=<password>,
        cursorclass=tormysql.cursor.DictCursor,
        autocommit=True,
        use_unicode=True,
        charset="utf8",
        **kwargs
    )

connection = yield self.pool.Connection()
...
# this actually will not close the connection, but put back into pool
connection.close()

你可以偷这个gist。它将为您进行池处理。有了它,您可以:

db.query("SELECT ..");

对于原子操作,或者从池中获取连接以获得更复杂的东西:

with (yield db.acquire(auto_commit=False)) as db:
    row = yield db.get("SELECT ... FOR UPDATE");
    ...
    yield db.execute("UPDATE ...");
    yield db.commit()

【讨论】:

  • 我试过 aiomysql ,这是前面提到的@xyres。但我不知道如何将游标对象传递给请求处理程序。 aiomysql 的创建池函数是一个异步函数。我不能在应用程序 init 中调用它。如果我尝试 TorMySQL 怎么能做到这一点?例如,我在应用程序 init 中创建了一个池。我想在 requesthandler 的初始化方法中创建一个连接游标。但是初始化方法不是异步方法,所以我不能在其中调用yield self.application.pool.Connection()。你对此有何建议。感谢您的回复。
  • @RasimAndıran 见add_callback。它是协程就绪的,所以你可以做IOLoop.current().add_callback(your_async_init)
猜你喜欢
  • 1970-01-01
  • 2021-09-03
  • 2021-05-08
  • 2014-08-07
  • 2019-02-14
  • 2016-09-02
  • 1970-01-01
  • 1970-01-01
  • 2015-04-16
相关资源
最近更新 更多