mysql 异步编程_怎么连接数据库-Python异步编程·aiohttp+aiomysql连接mysql数据库

上篇文章介绍了怎么写一个简单的服务器。接下来开始拓展一些基本功能。

数据库交互是十分常见的,今天我们就介绍一下怎么连接数据库--以mysql为例。

注意:此篇代码版本要求Python3.6以上,aiohttp 3.1以上(最新是3.4)。

拆分文件

由于数据库连接又需要配置地址密码等,最好放进一个配置文件中,我们先拆分出几个文件像这样:

配置文件conf.json专门放置诸如数据库连接配置等常数,

db.py是连接数据库的代码,

settings.py读取conf.json的配置,

views.py是各种url对应的视图函数。

配置文件在我们的项目中可以写成这样:

省略号部分填上自己的数据库表名,用户名,密码和地址。

update_interval暂时不用管是什么。

然后我们在settings.py读取配置:

数据共享

aiohttp.web给Application和request,response实现了一个collections.abc.MutableMapping接口,简单来说,就变成了类似dict的对象,以Application为例,可以这样存储数据:

from settings import config

app['config'] = config

即使在views.py中,也可以通过request.app读取:

打开http://127.0.0.1:8080/conf,就会看到:

当然,这只是个例子,实际可别这样暴露自己的配置文件。

读取了配置文件后,就要开始连接数据库了。

由于应该在开始运行时连接数据库,在程序停止运行时关闭连接,就得用到信号处理程序。

信号

信号处理程序没有返回值,可以修改传入参数。

通过按顺序订阅Application.on_startup和Application.on_cleanup信号可以依序设置Application的组件并拆除。

从aiohttp 3.0起,信号程序必须是协程,也就是异步的。

所以我们连接mysql需要用到一个异步连接库--aiomysql。基本语法和pymysql相似,就不再介绍了。

以下代码可以正确初始化一个aiomysql连接池:

但这段代码还是会有一个问题:

由于Application.on_startup和Application.on_cleanup彼此独立,互相不知道彼此的状态,结果就算前者发生异常,还是会执行后者的清理代码。

因此,实际上应该用Application.cleanup_ctx,代码改成这样:

然后在main.py中添加一行:

app.cleanup_ctx.append(mysql_engine)

Application.cleanup_ctx是一个存储异步的生成器的列表。不知道什么是异步的生成器?没关系,只要知道存储的是这个名词,不影响下面的理解。

Python3.6起才支持异步的生成器。Python3.5需要pip install async_generator。

在aiohttp的官方文档中这样介绍的:

每个异步生成器的代码中以yield分界,之前的代码在初始化时运行,相当于Application.on_startup部分,之后的代码执行清理部分,相当于Application.on_cleanup。

每个异步生成器只能有1个yield。

aiohttp可以保证清理部分只在初始化成功后才运行。

这样,我们就成功连接了mysql数据库,

假设有一个名为crawl_result的表,至少有2个字段id和url,

那么在views.py中可以这样执行sql,以获取数据库crawl_result表中id对应的url:

注意aiomysql的语法,先获取一个连接conn,再获取游标cur,之后基本上就是在处理cur有关的代码行前加个await,其他与pymysql一致。

运行一下:

这样就获取了表中id是8的url字段。

aiohttp连接数据库的基本操作就是如此了。

源码分析

上面说到,aiohttp可以保证Application.cleanup_ctx的清理部分代码一定在初始化成功后才执行,那么这是怎么实现的呢?

来看对应的源码部分:

首先,至少需要知道生成器的相关知识,不知道异步生成器没关系,下面以这个前提来简要分析一下:

__aiter__和__anext__其实就是__iter__和__next__的异步版本。

self就是Application.cleanup_ctx这个list,for cb in self是在循环这个列表。

it = cb(app).__aiter__()从当前生成器获取了一个迭代器it,之后await it.__anext__()让代码运行到yield部分,接着self.exits存储运行到yield部分的这个迭代器,_on_startup这部分结束。

_on_cleanup方法中,把self._exits反转后执行for循环,从末尾的异步生成器开始向前,每个生成器执行yield之后的清理程序。并且有一些诸如保证每个异步生成器只能有1个yield的异常处理代码。

可以看出,假如_on_startup部分最后一行之前的代码抛出异常,self.exits就不会存储数据,于是_on_cleanup里不会执行抛出异常的生成器中清理部分的代码。

这样,aiohttp就保证了yield之后的清理代码只会在初始化成功后运行。

今天的全部代码可以从https://github.com/lucays/toutiao/tree/master/16获取。

记得把conf.json中的省略号替换成自己数据库对应的配置噢。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值