内容简介:SanicDB 是为 Python 的异步 Web 框架 Sanic 方便操作 MySQL 而开发的工具,是对 aiomysql.Pool 的轻量级封装。Sanic 是异步IO的Web框架,同时用异步IO读写MySQL才能更大发挥它的效率。虽然这个模块叫做 SanicDB,...
SanicDB 是为 Python 的异步 Web 框架 Sanic 方便操作 MySQL 而开发的工具,是对 aiomysql.Pool 的轻量级封装。Sanic 是异步IO的Web框架,同时用异步IO读写MySQL才能更大发挥它的效率。虽然这个模块叫做 SanicDB,但是它可以用在任何异步IO操作MySQL的地方。
SanicDB的灵感来源于tornado里面的对MySQLdb(MySQL的 C语言 接口的Python封装)的操作,后来tornado把它去除了,就有人把这部分代码写成一个单独的模块叫做 torndb,torndb是对python-mysql的封装,不能进行异步操作。但是它很简洁,用起来已经非常习惯了。
在用Sanic的时候,发现有异步IO的aiomysql可以用,但是用起来还有点麻烦,于是就着手对aiomysql进行封装,既然aiomysql支持连接池,那就直接封装aiomysql.Pool吧。
首先,看看它的初始化
class SanicDB:
"""A lightweight wrapper around aiomysql.Pool for easy to use
"""
def __init__(self, host, database, user, password,
loop=None, sanic=None,
minsize=3, maxsize=5,
return_dict=True,
pool_recycle=7*3600,
autocommit=True,
charset = "utf8mb4", **kwargs):
'''
前面4个参数是对应数据库的;
loop 是你的应用程序中的事件循环(event_loop);
sanic 是你的Sanic 应用中的sanic 对象;
loop 和 sanic 两者只需提供一个即可,当同时存在时,连接数据库其实用的是sanic里面的loop,这在__init__()代码中可以看到。
minisize 和 maxsize 是连接池的个数限制;
return_dict 是返回的数据一条记录为一个dict,key是MySQL表的字段名,value是字段的值;
pool_recycle 是连接池重连的时间间隔,MySQL默认的连接闲置时间是8小时;
对MySQL的读写操作方法:
async def query(self, query, *parameters, **kwparameters):
async def execute(self, query, *parameters, **kwparameters):
async def get(self, query, *parameters, **kwparameters):
从代码中可以看到,以上三个函数都是调用的cursor的execute() 执行 SQL 命令,但是query(), get() 用于读操作返回数据,query返回全部数据(list),get只返回一条数据。
execute() 方法用来执行写操作,返回受影响的行ID。
上面三个函数都是一样的:
query 是要执行的SQL语句, 后面两个参数是用来参数化执行sql语句的。参数化执行sql是为了防止SQL注入的,那么参数化执行SQL是什么意思呢,举个例子就目标了。
比如,进行用户登录时,我们要执行一条SQL,Python拼接SQL如下:
sql = "select * from user where name='%s' and password='%s'" % (input_name, input_password)
input_name 和 input_password 都是用户输入的,如果用户想捣鬼,他把input_name 输入成 “ ‘ or 1 = 1 –”,拼接出来的sql就成了:
select * from user where name='' or 1 = 1 --' and password='anything'
or 后面的 1=1 就是True,而 — 后面都成了注释,这条语句不管input_name, input_password 是什么都可以执行,通过用户验证,达到了注入目的。
参数化执行SQL就是把拼接SQL的任务交给SanicDB(实际上是它后的aiomysql后面的pymysql),我们只把要拼接的参数当做*parameters传给读写方法即可:
mydb.query("select * from user where user=%s and password=%s", input_name, input_password)
更高级的封装:
query(), get(), execute() 就是基本的操作,在此基础上,做了进一步封装,让写应用更方便:
# 检查一个table中是否含有某字段为某值的记录
async def table_has(self, table_name, field, value):
# 把一个item插入一个表,item为dict,key是字段名,
# ignore_duplicated为True时,遇到唯一索引重复时不报错
async def table_insert(self, table_name, item, ignore_duplicated=True):
# 更新一个table的记录,updates是dict,key为字段名
async def table_update(self, table_name, updates, field_where, value_where):
示例
代码仓库中有两个示例:
test.py 是在普通asyncio程序中使用异步MySQL的例子
example.py 是在Sanic Web中使用的例子
特别说明一下,Sanic 对象 app 中还没有生成 event_loop 对象(它是在app.run() 之后生成的),所以在Sanic中初始化SanicDB时(app.run())之前,运行sql语句会报错。如果需要创建连接后初始化运行一些SQL操作,可以利用Sanic的Listner:
@app.listener('before_server_start')
async def setup_db(app, loop):
app.db = await db_setup()
以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网
猜你喜欢:本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。