我們已經(jīng)創(chuàng)建了一個(gè)能建立數(shù)據(jù)庫(kù)連接的函數(shù) connect_db ,但它本身并 不是很有用??偸莿?chuàng)建或關(guān)閉數(shù)據(jù)庫(kù)連接是相當(dāng)?shù)托У模晕覀儠?huì)讓連接 保持更長(zhǎng)時(shí)間。因?yàn)閿?shù)據(jù)庫(kù)連接封裝了事務(wù),我們也需要確保同一時(shí)刻只有 一個(gè)請(qǐng)求使用這個(gè)連接。那么,如何用 Flask 優(yōu)雅地實(shí)現(xiàn)呢?

這該是應(yīng)用環(huán)境上場(chǎng)的時(shí)候了。那么,讓我們開始吧。

Flask 提供了兩種環(huán)境(Context):應(yīng)用環(huán)境(Application Context)和 請(qǐng)求環(huán)境(Request Context)。暫且你所需了解的是,不同環(huán)境有不同的 特殊變量。例如 request 變量與當(dāng)前請(qǐng)求的請(qǐng)求對(duì)象有關(guān), 而 g 是與當(dāng)前應(yīng)用環(huán)境有關(guān)的通用變量。我們?cè)谥髸?huì)深 入了解它們。

現(xiàn)在你只需要知道可以安全地在 g 對(duì)象存儲(chǔ)信息。

那么你何時(shí)把數(shù)據(jù)庫(kù)連接存放到它上面?你可以寫一個(gè)輔助函數(shù)。這個(gè)函數(shù) 首次調(diào)用的時(shí)候會(huì)為當(dāng)前環(huán)境創(chuàng)建一個(gè)數(shù)據(jù)庫(kù)連接,調(diào)用成功后返回已經(jīng)建 立好的連接:

def get_db():
    """Opens a new database connection if there is none yet for the
    current application context.
    """
    if not hasattr(g, 'sqlite_db'):
        g.sqlite_db = connect_db()
    return g.sqlite_db

于是現(xiàn)在我們知道如何連接到數(shù)據(jù)庫(kù),但如何妥善斷開連接呢?為此, Flask 提供了 teardown_appcontext() 裝飾器。它將 在每次應(yīng)用環(huán)境銷毀時(shí)執(zhí)行:

@app.teardown_appcontext
def close_db(error):
    """Closes the database again at the end of the request."""
    if hasattr(g, 'sqlite_db'):
        g.sqlite_db.close()

teardown_appcontext() 標(biāo)記的函數(shù)會(huì)在每次應(yīng)用環(huán)境 銷毀時(shí)調(diào)用。這意味著什么?本質(zhì)上,應(yīng)用環(huán)境在請(qǐng)求傳入前創(chuàng)建,每當(dāng)請(qǐng) 求結(jié)束時(shí)銷毀。銷毀有兩種原因:一切正常(錯(cuò)誤參數(shù)會(huì)是 None )或發(fā) 生異常,后者情況中,錯(cuò)誤會(huì)被傳遞給銷毀時(shí)函數(shù)。

好奇這些環(huán)境的意義?閱讀 應(yīng)用上下文 文檔了解更多。

閱讀 Flask 創(chuàng)建數(shù)據(jù)庫(kù) 以繼續(xù)。

提示:

我該把這些代碼放在哪?

如果你一直遵循教程,你應(yīng)該會(huì)問(wèn)從此以后的步驟產(chǎn)生的代碼放在 什么地方。邏輯上來(lái)講,應(yīng)該按照模塊來(lái)組織函數(shù),即把你新的 get_dbclose_db 函數(shù)放在之前的 connect_db 函數(shù)下面(逐行復(fù)刻教程)。

如果你需要來(lái)找準(zhǔn)定位,可以看一下 示例源碼 是怎么組織的。 在 Flask 中,你可以把你應(yīng)用中所有的代碼放在一個(gè) Python 模塊里。但你無(wú)需這么做,而且在你的應(yīng)用 規(guī)模擴(kuò)大 以后,這顯然不妥。