tornado+peewee

Easter79
• 阅读 915
前言:
  • 需要异步操作MySQL,又要用orm,使用sqlalchemy需要加celery,觉得比较麻烦,选择了peewee-async
开发环境 python3.6.8+peewee-async0.5.12+peewee2.10.2
  • 数据库:MySQL,使用peewee-async需要依赖库 pip install aiomysql

  • peewee-async,对peewee版本只支持peewee<=2.10.2,>=2.8.0

  • python3.5以后使用async和await关键字实现原生协程,也可以使用tornado的gen模块下coroutine实现协程,或者asyncio模块实现协程,下文统一使用async和await

tornado 异步调用MySQL

  • 爬坑

    • 最初遇到的坑,使用了最新版的peewee,连接池连接,也使用了async和await协程,但是怎么调用都会阻塞,后来发现不是阻塞单个协程,是阻塞了整个进程,因为tornado是单进程,必须数据库也使用异步操作,才能不阻塞整个进程

    • pip install peewee-async 的时候默认会安装符合版本要求的peewee

    • 查看peewee-async 模块的MySQLDatabase,继承了AsyncDatabase和peewee.MySQLDatabase,AsyncDatabase方法全部使用协程实现异步

  • peewee-async 连接MySQL,返回database对象

    • 单连接

      import peewee_async
      # db = peewee_async.MySQLDatabase(database_name, host, port, user, password)
      #  或者,将自己的数据库信息封装到字典中
      db_setting = {
              "user": "root",
              "password": "xxxxxx",
              "host": "127.0.0.1",
              "port": 3306,
              "database": "test"
          }
      db = peewee_async.MySQLDatabase(**db_setting)
      
    • 连接池

      from playhouse.shortcuts import RetryOperationalError
      from peewee_async import PooledMySQLDatabase
      #  可以自动重新连接的连接池
      class RetryMySQLDatabase(RetryOperationalError, PooledMySQLDatabase):
          _instance = None
      
          @staticmethod
          def get_db_instance():
              if not RetryMySQLDatabase._instance:
                  RetryMySQLDatabase._instance = RetryMySQLDatabase(database_name,
                                                                  host, port, user, password,
                                                                  max_connections=10)
              return RetryMySQLDatabase._instance
      
      db = RetryMySQLDatabase.get_db_instance()
      
  • 返回的database对象的一些常用方法

    • get_tables() 返回列表,当前数据库的所有表名

    • get_columns(table_name) 传参表名,返回列表,包含ColumnMetadata对象,字段信息

    • create_tables()

      第一个参数为列表,包含要创建的表model 第二个参数safe, 不传默认为False,建表的时候如果表已经存在会报错,可以加safe=True

    • is_closed() 判断当前连接是否关闭

    • close() 关闭连接

  • peewee

    • peewee 模块可以参照官方文档用法,和sqlalchemy差别不大,为了下面的操作,暂时建一个model

    book.py

    # 集中写一个basemodel,将数据库对象绑定在model上,类才能映射到数据库中的表
    class BaseModel(Model):
        class Meta:
            database = db
    class Book(BaseModel):
        book_id = PrimaryKeyField() # int 主键自增,在peewee3.10 版本中新增了字段AutoField,表示主键自增
        book_name = CharField(max_length=100, verbose_name="书名")
        # 鉴于篇幅, 作者表不写,外键第一个参数为model类名,to_field表示关联的字段
        book_auth = ForeignKeyField(User, to_field="user_id", verbose_name="作者id")
    
  • peewee-async Manager

    • 管理数据库操作,实现异步操作数据库必须使用Manager,查看源码可以看到,类中的get, create, execute等方法都是使用装饰器@asyncio.coroutine加yield from,在原有的数据库操作基础上做了封装

    • 初始化传入数据库连接对象,生成manager对象,使用该对象完成数据库操作,在tornado中一般选择绑定到app上

      from tornado.web import RequestHandler from tornado import gen import tornado.ioloop from book import Book

      class RegHandler(RequestHandler): async def get(self): # 在handler类中可以使用绑定到app上的manager对象执行操作,因为是异步操作需要使用await关键字 # 以下两种查询方式返回结果对象格式不同 book_res = await self.application.objects.get(Book, book_name="简爱") id = book_res.book_id # 只有调用了execute方法才是执行,query打印可以看到只是生成了sql语句 # 为保证异步调用必须使用peewee-async manager生成的对象执行操作函数,不能使用model的execute执行,会同步阻塞 query = Book.select().where(Book.username=="简爱") # execute执行返回AsyncQueryWrapper对象,如果有值可以通过下标取出每个book对象 # query 对象执行前可以调用dicts()方法,返回对象内容为字典格式 # query.tuples() 返回对象内容为元组格式,相当于sqlalchemy,fetchall() # 其他方法或者属性有需要的可以使用dir()方法和getattr()方法查看属性,以及属性调用后返回值 book_res = await self.application.objects.execute(query.dicts()) pass async def post(self): from tornado.escape import json_decode body = json_decode(self.request.body) # 增 # 如果参数是字典格式,且key值对应字段名称,可以使用peewee model里面的insert方法 await self.application.objects.execute(Book.insert(body)) # 或者使用封装的create方法,create方法源码还是调用了model类的insert方法 await self.application.objects.create(Book, boo_name=body.get("book"), book_auth=2) pass app = tornado.web.Application([ (r"/book", BookHandler) ])

      if name == 'main': app = tornado.web.Application(urlpaten) import peewee_async # 将manager对象绑定到app上 app.objects = peewee_async.Manager(database) server = httpserver.HTTPServer(app, xheaders=True) server.listen(80) tornado.ioloop.IOLoop.current().start()


  • 初步介绍先先写到这里,通过上述介绍使用peewee和peewee-async没有大问题,后面会通过详细功能具体详细介绍使用,细小的api建议看官方文档

  • 有问题欢迎指出,随时修正

点赞
收藏
评论区
推荐文章
blmius blmius
3年前
MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1
文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s
待兔 待兔
4个月前
手写Java HashMap源码
HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程22
Jacquelyn38 Jacquelyn38
3年前
2020年前端实用代码段,为你的工作保驾护航
有空的时候,自己总结了几个代码段,在开发中也经常使用,谢谢。1、使用解构获取json数据let jsonData  id: 1,status: "OK",data: 'a', 'b';let  id, status, data: number   jsonData;console.log(id, status, number )
Stella981 Stella981
3年前
Python3:sqlalchemy对mysql数据库操作,非sql语句
Python3:sqlalchemy对mysql数据库操作,非sql语句python3authorlizmdatetime2018020110:00:00coding:utf8'''
Easter79 Easter79
3年前
Twitter的分布式自增ID算法snowflake (Java版)
概述分布式系统中,有一些需要使用全局唯一ID的场景,这种时候为了防止ID冲突可以使用36位的UUID,但是UUID有一些缺点,首先他相对比较长,另外UUID一般是无序的。有些时候我们希望能使用一种简单一些的ID,并且希望ID能够按照时间有序生成。而twitter的snowflake解决了这种需求,最初Twitter把存储系统从MySQL迁移
Wesley13 Wesley13
3年前
mysql设置时区
mysql设置时区mysql\_query("SETtime\_zone'8:00'")ordie('时区设置失败,请联系管理员!');中国在东8区所以加8方法二:selectcount(user\_id)asdevice,CONVERT\_TZ(FROM\_UNIXTIME(reg\_time),'08:00','0
Wesley13 Wesley13
3年前
00:Java简单了解
浅谈Java之概述Java是SUN(StanfordUniversityNetwork),斯坦福大学网络公司)1995年推出的一门高级编程语言。Java是一种面向Internet的编程语言。随着Java技术在web方面的不断成熟,已经成为Web应用程序的首选开发语言。Java是简单易学,完全面向对象,安全可靠,与平台无关的编程语言。
Wesley13 Wesley13
3年前
MySQL部分从库上面因为大量的临时表tmp_table造成慢查询
背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_
为什么mysql不推荐使用雪花ID作为主键
作者:毛辰飞背景在mysql中设计表的时候,mysql官方推荐不要使用uuid或者不连续不重复的雪花id(long形且唯一),而是推荐连续自增的主键id,官方的推荐是auto_increment,那么为什么不建议采用uuid,使用uuid究
Python进阶者 Python进阶者
10个月前
Excel中这日期老是出来00:00:00,怎么用Pandas把这个去除
大家好,我是皮皮。一、前言前几天在Python白银交流群【上海新年人】问了一个Pandas数据筛选的问题。问题如下:这日期老是出来00:00:00,怎么把这个去除。二、实现过程后来【论草莓如何成为冻干莓】给了一个思路和代码如下:pd.toexcel之前把这
Easter79
Easter79
Lv1
今生可爱与温柔,每一样都不能少。
文章
2.8k
粉丝
5
获赞
1.2k