標籤:ati ica 自己的 建立資料庫 thread .config 多少 必須 不同
一、設定檔
和django不同的是,django會為我們提供配置好的setting檔案,我們需要的配置都可以自動添加在setting檔案中即可,但是flask不是這樣,它是通過在內部為我們提供多種設定檔的介面,我們按照介面配置相關配置。簡單介紹如下幾種:
方式一:
如下,是我們入門告訴大家的配置方式,可以看出config本質上是一個字典(內部繼承dict或者有__setitem__方法),通過給字典添加索引值對的方式可以實現配置,但是像這種方式把大幅的配置代碼寫在主要程式碼中,顯然不符合編程規範,所以不推薦這樣使用,當然flask也為我們其他辦法。
方式二:
如下,將配置內容寫在py檔案中,通過讀取檔案的形式,應用程式啟動的時候回自動載入設定檔中的配置,注意一點的是,設定檔預設需要要放在程式root_path目錄,如果instance_relative_config為True,則就是instance_path目錄。
方式三:
如下配置環境變數的方式,將設定檔配置成環境變數,然後通過app.config.from_envvar(‘環境變數名‘)讀取環境變數中的設定檔,其內部同樣還是調用from_pyfile方法,本質是一樣,同樣設定檔放置目錄同方式二。
方式四:
通過將配置資訊配置在類中,按照app.config.from_object(“python類或類的路徑”)方式載入配置,這樣的方式不但可以將配置資訊和邏輯代碼分離,還可以做到將不同層級的配置進行分離,局部配置和全域配置分離,不同應用的配置也寫成不同的配置類,局部設定繼承全域配置,很靈活。為推薦的配置方式。
setting檔案樣本:
class BaseConfig(object): ‘‘‘ 放置全域配置 ‘‘‘ DB = ‘127.0.0.1‘ print("test BaseConfig")class TestConfig(BaseConfig): ‘‘‘ 放置局部配置 ‘‘‘ print("test TestConfig")class DevConfig(BaseConfig): ‘‘‘ 放置局部配置 ‘‘‘ print("test DevConfig")class ProConfig(BaseConfig): ‘‘‘ 放置局部配置 ‘‘‘ print("test ProConfig")
二、藍圖
在之前的講解中我們都是將所有的應用程式寫在同一個py檔案之中,顯然這也不是很合理的吧。我們應該向django中一樣,將不同應用單獨分開,利用然後只用一個啟動程式檔案即可。在flask中可以用藍圖(Blueprint)實現,如下介紹中小型項目,藍圖為應用提供目錄劃分。
mange.py檔案代碼執行個體:
import fcrm #引用項目模組,會執行模組中的__init__.py檔案if __name__ == ‘__main__‘: fcrm.app.run(port=8001) #app在fcrm模組中__init__.py檔案執行個體化
__init__.py檔案代碼:
from flask import Flaskfrom .views import account #引入視圖檔案夾views下的account應用from .views import orderapp = Flask(__name__)print(app.root_path)app.register_blueprint(account.account) #藍圖註冊應用app.register_blueprint(order.order)
account應用代碼:
from flask import Blueprint,render_templateaccount = Blueprint(‘account‘,__name__)@account.route(‘/login‘)def login(): # return ‘Login‘ return render_template(‘login.html‘)
三、資料庫連接池
不像django架構,flask架構沒有為我們提供內建的資料庫,因此我們只能自己引入諸如pymysql等模組,才能進行資料庫的操作,但是具體該怎麼做呢?可能我們可以直接在使用的地方串連資料庫就好,如下:
import pymysqlconn = pymysql.connect(.....)cursor = conn.cursor()cursor.execute(‘select * from tb where id > %s‘,[5,])result = cursor.fetchall()cursor.close()conn.close()print(result)
但是像上述這種情況,每次請求反覆建立資料庫連接,串連數太多,顯然肯定不是很合理,生產中切記這樣串連資料庫。那我們是不是又會想到如下的解決辦法呢?提前建立串連,供各個視圖使用,不用重複建立資料庫連接。顯然這在單線程下是可行的,但是如果是多線程,我們就為了不使多個使用者操作資料庫操作資料庫,必須加鎖處理。但是這樣使得多線程失去意義。代碼如下:
import pymysqlimport threadingfrom threading import RLockLOCK = 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()
那我們 該怎麼做呢?我們就用到一個資料連線池的東西。DBUtils是Python的一個用於實現資料庫連接池的模組。安裝方式pip install DBUtils,但是在講資料庫連接池之前,我們先介紹一個本地線程的概念,本地線程其實就為每一個線程做唯一的標識,用於儲存此線程的資料,如下執行個體:
import threadingimport time# 本地線程對象local_values = threading.local()def func(num): """ # 第一個線程進來,本地線程對象會為他建立一個 # 第二個線程進來,本地線程對象會為他建立一個 { 線程1的唯一標識:{name:1}, 線程2的唯一標識:{name:2}, } :param num: :return: """ local_values.name = num # 4 time.sleep(2) #local_values.name,去local_values中根據自己的唯一標識作為key,擷取value中name對應的值 print(local_values.name, threading.current_thread().name)for i in range(5): th = threading.Thread(target=func, args=(i,), name=‘線程%s‘ % i) th.start()
資料庫連接池模式一:
通過本地線程實現,為每個線程建立一個串連,線程即使調用了close方法,也不會關閉,只是把串連重新放到串連池,供自己線程再次使用。當線程終止時,串連自動關閉。如下:
from DBUtils.PersistentDB import PersistentDBimport pymysqlPOOL = 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() cursor = conn.cursor() cursor.execute(‘select * from tb1‘) result = cursor.fetchall() cursor.close() conn.close() #不是真的關閉,而是假的關閉。for i in range(10): t = threading.Thread(target=func) t.start()
資料庫連接池模式二:
建立一批串連到串連池,供所有線程共用使用。PS:由於pymysql、MySQLdb等threadsafety值為1,所以該模式串連池中的線程會被所有線程共用。如下:
import timeimport pymysqlimport threadingfrom DBUtils.PooledDB import PooledDB, SharedDBConnectionPOOL = 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() cursor = conn.cursor() cursor.execute(‘select * from tb1‘) result = cursor.fetchall() conn.close()func()
python之路_flask架構_flask架構基礎(2)