示例代碼:
from loguru import logger
from pymongo import MongoClient
from pymongo.errors import ConnectionFailurefrom llm_engineering.settings import settingsclass MongoDatabaseConnector:_instance: MongoClient | None = Nonedef __new__(cls, *args, **kwargs) -> MongoClient:if cls._instance is None:try:cls._instance = MongoClient(settings.DATABASE_HOST)except ConnectionFailure as e:logger.error(f"Couldn't connect to the database: {e!s}")raiselogger.info(f"Connection to MongoDB with URI successful: {settings.DATABASE_HOST}")return cls._instanceconnection = MongoDatabaseConnector()
詳細解釋
-
導入依賴模塊
from loguru import logger
- 作用:導入
loguru
庫中的logger
對象。這個對象用于記錄日志信息,比標準庫中的 logging 更加方便和直觀。 - 舉例:當程序運行時,可以用
logger.info("提示信息")
打印一條信息,比如記錄連接成功或失敗的日志。
from pymongo import MongoClient
- 作用:導入
pymongo
庫中的MongoClient
類。這個類用來創建與 MongoDB 數據庫的連接。 - 舉例:假如你需要連接一個 MongoDB 數據庫,其地址為
"mongodb://127.0.0.1:27017"
,就可以用MongoClient("mongodb://127.0.0.1:27017")
來創建連接對象。
from pymongo.errors import ConnectionFailure
- 作用:從
pymongo
庫中導入ConnectionFailure
異常類,當連接數據庫失敗時,這個異常會被拋出。 - 舉例:如果數據庫地址錯誤或者數據庫沒有啟動,會拋出
ConnectionFailure
異常,我們可以捕獲這個異常并記錄錯誤日志。
from llm_engineering.settings import settings
- 作用:導入項目中
llm_engineering.settings
模塊中的settings
對象。這個對象通常存儲配置參數,比如數據庫的 URI 地址。 - 舉例:假設在
settings
中有定義DATABASE_HOST = "mongodb://127.0.0.1:27017"
,那么代碼會使用這個地址來連接數據庫。
- 作用:導入
-
定義 MongoDatabaseConnector 類
class MongoDatabaseConnector:_instance: MongoClient | None = None
- 作用:定義一個類
MongoDatabaseConnector
,用來管理 MongoDB 的連接。這里使用了一個類變量_instance
來存儲連接實例。 - 解釋:
_instance
初始值為None
,表示當前還沒有創建數據庫連接。類型提示MongoClient | None
表示這個變量可能是一個MongoClient
對象,也可能是None
。
- 作用:定義一個類
-
重寫 new 方法實現單例模式
def __new__(cls, *args, **kwargs) -> MongoClient:if cls._instance is None:try:cls._instance = MongoClient(settings.DATABASE_HOST)except ConnectionFailure as e:logger.error(f"Couldn't connect to the database: {e!s}")raiselogger.info(f"Connection to MongoDB with URI successful: {settings.DATABASE_HOST}")return cls._instance
-
作用:
__new__
是 Python 中的一個特殊方法,用于在創建實例之前進行控制。這里重寫它實現了“單例模式”,即無論你創建多少次這個類的實例,都只會返回同一個 MongoClient 連接對象。 -
詳細步驟:
-
判斷是否已存在連接:
if cls._instance is None:
- 意思:如果
_instance
還是None
(表示還沒有連接實例),則繼續創建新的連接。
- 意思:如果
-
嘗試建立數據庫連接:
try:cls._instance = MongoClient(settings.DATABASE_HOST)
- 作用:調用
MongoClient
構造函數,使用settings.DATABASE_HOST
(例如"mongodb://127.0.0.1:27017"
)來創建數據庫連接。 - 舉例:假設
settings.DATABASE_HOST
定義為"mongodb://192.168.1.100:27017"
,那么代碼會試圖連接到 IP 為 192.168.1.100、端口為 27017 的 MongoDB 實例。
- 作用:調用
-
異常處理:
except ConnectionFailure as e:logger.error(f"Couldn't connect to the database: {e!s}")raise
- 作用:如果連接失敗(例如數據庫沒有啟動、地址錯誤等),會捕獲
ConnectionFailure
異常。 - 解釋:程序會通過
logger.error
輸出錯誤日志,然后使用raise
將異常繼續拋出,確保調用者知道連接出了問題。 - 舉例:若連接失敗并拋出異常,比如錯誤代碼為 10061(連接被拒絕),錯誤日志會顯示
"Couldn't connect to the database: [錯誤信息]"
。
- 作用:如果連接失敗(例如數據庫沒有啟動、地址錯誤等),會捕獲
-
記錄成功日志:
logger.info(f"Connection to MongoDB with URI successful: {settings.DATABASE_HOST}")
- 作用:不論是首次連接還是復用已有連接,都記錄一條信息日志,表明連接成功。
- 舉例:如果成功連接到
"mongodb://192.168.1.100:27017"
,日志中會顯示"Connection to MongoDB with URI successful: mongodb://192.168.1.100:27017"
。
-
返回連接實例:
return cls._instance
- 作用:返回創建好的 MongoClient 實例。這樣,無論何時調用
MongoDatabaseConnector()
,最終返回的都是同一個連接實例。
- 作用:返回創建好的 MongoClient 實例。這樣,無論何時調用
-
-
-
創建連接實例
connection = MongoDatabaseConnector()
- 作用:調用
MongoDatabaseConnector()
來獲取 MongoDB 的連接實例。 - 解釋:這行代碼實際上會觸發上面定義的
__new__
方法,判斷是否需要創建新連接或直接返回已有連接。最終,變量connection
存儲了一個MongoClient
對象。 - 舉例:如果第一次調用時創建連接,則
connection
可能代表一個連接到"mongodb://192.168.1.100:27017"
的 MongoClient 實例;后續再調用時將復用這個實例。
- 作用:調用
總結
- 單例模式:該代碼使用了單例模式保證整個程序中只會創建一個數據庫連接。這樣可以避免重復創建連接資源,提升效率。
- 錯誤處理:使用
try...except
捕獲連接失敗的情況,并通過日志記錄錯誤信息,然后拋出異常,確保問題不會被忽略。 - 日志記錄:通過
loguru
的logger
對象,詳細記錄了連接的成功與失敗狀態,方便排查問題。 - 實際場景舉例:
假設你的數據庫地址為"mongodb://192.168.1.100:27017"
,第一次執行MongoDatabaseConnector()
時:- 程序檢查
_instance
是None
; - 連接成功后,將
MongoClient("mongodb://192.168.1.100:27017")
賦值給_instance
; - 輸出日志 “Connection to MongoDB with URI successful: mongodb://192.168.1.100:27017”;
- 將該連接實例返回并賦值給
connection
。
如果之后再調用MongoDatabaseConnector()
,程序就直接返回已存在的連接實例,不再重新連接。
- 程序檢查
這樣寫的好處是節省資源、簡化連接管理,同時通過日志記錄幫助開發者快速定位數據庫連接的問題。