數據庫:MySQL,使用peewee-async須要依賴庫 pip install aiomysqlpython
peewee-async,對peewee版本只支持peewee<=2.10.2,>=2.8.0mysql
python3.5之後使用async和await關鍵字實現原生協程,也可使用tornado的gen模塊下coroutine實現協程,或者asyncio模塊實現協程,下文統一使用async和awaitweb
最初遇到的坑,使用了最新版的peewee,鏈接池鏈接,也使用了async和await協程,可是怎麼調用都會阻塞,後來發現不是阻塞單個協程,是阻塞了整個進程,由於tornado是單進程,必須數據庫也使用異步操做,才能不阻塞整個進程sql
pip install peewee-async 的時候默認會安裝符合版本要求的peewee,想用最新的peewee模塊可使用--pre數據庫
查看peewee-async 模塊的MySQLDatabase,繼承了AsyncDatabase和peewee.MySQLDatabase,AsyncDatabase方法所有使用協程實現異步json
單鏈接api
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)
鏈接池app
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()
get_tables() 返回列表,當前數據庫的全部表名異步
get_columns(table_name) 傳參表名,返回列表,包含ColumnMetadata對象,字段信息async
create_tables()
第一個參數爲列表,包含要建立的表model
第二個參數safe, 不傳默認爲False,建表的時候若是表已經存在會報錯,能夠加safe=True
is_closed() 判斷當前鏈接是否關閉
close() 關閉鏈接
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")
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建議看官方文檔
有問題歡迎指出,隨時修正