Flask請求擴充套件和資料庫連線池
阿新 • • 發佈:2018-12-30
1.1.Flask之請求擴充套件
#!/usr/bin/env python # -*- coding:utf-8 -*- from flask import Flask, Request, render_template app = Flask(__name__, template_folder='templates') app.debug = True @app.before_first_request def before_first_request1(): print('before_first_request1') @app.before_first_request所有請求擴充套件def before_first_request2(): print('before_first_request2') @app.before_request def before_request1(): Request.nnn = 123 print('before_request1') @app.before_request def before_request2(): print('before_request2') @app.after_request def after_request1(response):print('before_request1', response) return response @app.after_request def after_request2(response): print('before_request2', response) return response @app.errorhandler(404) def page_not_found(error): return 'This page does not exist', 404 @app.template_global() defsb(a1, a2): return a1 + a2 @app.template_filter() def db(a1, a2, a3): return a1 + a2 + a3 @app.route('/') def hello_world(): return render_template('hello.html') if __name__ == '__main__': app.run()
(1)基於before_request 做使用者登入認證
@app.before_request def process_request(*args,**kwargs): #登入頁面不需要驗證 if request.path == '/login': return None user = session.get('user_info') if user: return None return redirect('/login')
(2)before_request和after_request執行順序
from flask import Flask,render_template,request,redirect,session,url_for app = Flask(__name__) app.debug = True app.secret_key = 'abcdef' @app.before_request def process_request1(*args,**kwargs): print('request1進來') @app.before_request def process_request2(*args,**kwargs): print('request2進來') @app.after_request def process_response1(response): print('response1走了') return response @app.after_request def process_response2(response): print('response2走了') return response @app.route('/index',methods=['GET']) def index(): print('index函式') return 'hello' if __name__ == '__main__': app.run()
執行結果:
可以看出:
- before_request是從上往下的執行順序(先1後2)
- after_response是從下往上的執行順序(先2後1)
(3)請求攔截後,response所有都執行
在process_request 新增一個return
@app.before_request def process_request1(*args,**kwargs): print('request1進來') return "攔截"
再執行結果如下:
(4)定製錯誤資訊
當訪問不存在的url,可以自己定製錯誤資訊頁面
@app.errorhandler(404) def error_404(arg): return '404錯誤'
1.2.資料庫連線池
DBUtils是Python的一個用於實現資料庫連線池的模組。
安裝
進官網下載https://pypi.org/project/DBUtils/1.2/,然後安裝:
連線池有兩種方式
(1)模式一
為每個執行緒建立連線,執行緒即使呼叫了close方法,也不會關閉,只是把連線重新放到連線池,供自己執行緒再次使用。當執行緒終止時,連線自動關閉。
POOL = PersistentDB( creator=pymysql, # 使用連結資料庫的模組 maxusage=None, # 一個連結最多被重複使用的次數,None表示無限制 setsession=[], # 開始會話前執行的命令列表。如:["set datestyle to ...", "set time zone ..."] ping=0, # ping MySQL服務端,檢查是否服務可用。# 如:0 = None = never, 1 = default = whenever it is requested, 2 = when a cursor is created, 4 = when a query is executed, 7 = always closeable=False, # 如果為False時, conn.close() 實際上被忽略,供下次使用,再執行緒關閉時,才會自動關閉連結。如果為True時, conn.close()則關閉連結,那麼再次呼叫pool.connection時就會報錯,因為已經真的關閉了連線(pool.steady_connection()可以獲取一個新的連結) threadlocal=None, # 本執行緒獨享值得物件,用於儲存連結物件,如果連結物件被重置 host='127.0.0.1', port=3306, user='root', password='123', database='pooldb', charset='utf8' ) def func(): conn = POOL.connection(shareable=False) cursor = conn.cursor() cursor.execute('select * from tb1') result = cursor.fetchall() cursor.close() conn.close() func()View Code
(2)模式二,推薦使用的方式
建立多個連線,多執行緒來時,去獲取,
import time import pymysql import threading from DBUtils.PooledDB import PooledDB, SharedDBConnection POOL = PooledDB( creator=pymysql, # 使用連結資料庫的模組 maxconnections=6, # 連線池允許的最大連線數,0和None表示不限制連線數 mincached=2, # 初始化時,連結池中至少建立的空閒的連結,0表示不建立 maxcached=5, # 連結池中最多閒置的連結,0和None不限制 maxshared=3, # 連結池中最多共享的連結數量,0和None表示全部共享。PS: 無用,因為pymysql和MySQLdb等模組的 threadsafety都為1,所有值無論設定為多少,_maxcached永遠為0,所以永遠是所有連結都共享。 blocking=True, # 連線池中如果沒有可用連線後,是否阻塞等待。True,等待;False,不等待然後報錯 maxusage=None, # 一個連結最多被重複使用的次數,None表示無限制 setsession=[], # 開始會話前執行的命令列表。如:["set datestyle to ...", "set time zone ..."] ping=0, # ping MySQL服務端,檢查是否服務可用。# 如:0 = None = never, 1 = default = whenever it is requested, 2 = when a cursor is created, 4 = when a query is executed, 7 = always host='127.0.0.1', port=3306, user='root', password='123', database='pooldb', charset='utf8' ) def func(): # 檢測當前正在執行連線數的是否小於最大連結數,如果不小於則:等待或報raise TooManyConnections異常 # 否則 # 則優先去初始化時建立的連結中獲取連結 SteadyDBConnection。 # 然後將SteadyDBConnection物件封裝到PooledDedicatedDBConnection中並返回。 # 如果最開始建立的連結沒有連結,則去建立一個SteadyDBConnection物件,再封裝到PooledDedicatedDBConnection中並返回。 # 一旦關閉連結後,連線就返回到連線池讓後續執行緒繼續使用。 conn = POOL.connection() # print(th, '連結被拿走了', conn1._con) # print(th, '池子裡目前有', pool._idle_cache, '\r\n') cursor = conn.cursor() cursor.execute('select * from tb1') result = cursor.fetchall() conn.close() func()
如果沒有連線池,使用pymysql來連線資料庫時,單執行緒應用完全沒有問題,但如果涉及到多執行緒應用那麼就需要加鎖,一旦加鎖那麼連線勢必就會排隊等待,當請求比較多時,效能就會降低了。
import pymysql import threading from threading import RLock LOCK = RLock() CONN = pymysql.connect(host='127.0.0.1', port=3306, user='root', password='123', database='pooldb', charset='utf8') def task(arg): with LOCK: cursor = CONN.cursor() cursor.execute('select * from tb1') result = cursor.fetchall() cursor.close() print(result) for i in range(10): t = threading.Thread(target=task, args=(i,)) t.start()