SQLAlchemy學(xué)習(xí)筆記(一)
為什么要使用SQLAlchemy?
將你的代碼抽象出來不依賴與數(shù)據(jù)庫的類型和某種數(shù)據(jù)庫自身的的獨特性,SQLAlchemy提供了強大又通用的語句和類型,你不在需要考慮你所選用數(shù)據(jù)庫的實現(xiàn)及其廠商。SQLAlchemy同樣使得將數(shù)據(jù)邏輯從Oracle或者PostgreSQL到你的應(yīng)用程序的數(shù)據(jù)庫或者其他數(shù)據(jù)倉庫。它將將對數(shù)據(jù)庫的操作在提交給數(shù)據(jù)庫之前進行了統(tǒng)一的規(guī)范和轉(zhuǎn)義。這樣就避免了一些常見的問題例如數(shù)據(jù)庫注入攻擊。
SQLAlchemy通過兩種主要的數(shù)據(jù)庫訪問方式提供了強大的靈活性:SQL表達式和ORM。這些方式可以單獨使用也可以結(jié)合使用,完全取決于你的喜好和應(yīng)用程序的需要。
SQLAlchemy Core和 SQL Expression Language
SQL表達式是一種比較Pythonic的方式取代原始的SQL語句,它是一個對原始SQL語言的初級抽象,雖然聚焦于具體的數(shù)據(jù)庫,然而,通過對多數(shù)的后端數(shù)據(jù)庫提供了統(tǒng)一的語言實現(xiàn)了訪問方式的統(tǒng)一。
ORM
SQLAlchemy ORM類似于你在其他語言中可能遇到的許多其他對象關(guān)系映射器(ORM)。它關(guān)注于應(yīng)用程序的領(lǐng)域模型,并利用工作模式單元來維護對象狀態(tài)。它還在SQL表達式語言之上提供了高級抽象,使用戶能夠以更習(xí)慣的方式工作。您可以混合使用ORM和SQL表達式語言來創(chuàng)建非常強大的應(yīng)用程序。ORM利用了一個聲明式系統(tǒng),該系統(tǒng)與許多其他ORM(如Ruby on Rails中的ORM)使用的活動記錄系統(tǒng)類似。
雖然ORM非常有用,但您必須記住,在關(guān)聯(lián)類的方式和底層數(shù)據(jù)庫關(guān)系的工作方式之間是有區(qū)別的。在第6章中,我們將更全面地探討這種方法如何影響您的實現(xiàn)。
在SQLAlchemy Core和ORM之間如何選擇?
在開始使用SQLAlchemy構(gòu)建應(yīng)用程序之前,您需要決定是主要使用ORM還是Core。選擇SQLAlchemy Core或ORM作為應(yīng)用程序的主要數(shù)據(jù)訪問層通常取決于幾個因素和個人偏好。
這兩種模式使用的語法略有不同,但是Core和ORM之間最大的區(qū)別是將數(shù)據(jù)視為模式或業(yè)務(wù)對象。SQLAlchemy Core有一個以模式為中心的視圖,它與傳統(tǒng)SQL一樣,主要關(guān)注表、鍵和索引結(jié)構(gòu)。SQLAlchemy Core在數(shù)據(jù)倉庫、報告、分析和其他場景中非常出色,在這些場景中,能夠嚴(yán)格控制查詢或?qū)ξ唇5臄?shù)據(jù)進行操作非常有用。強大的數(shù)據(jù)庫連接池和結(jié)果集優(yōu)化非常適合處理大量數(shù)據(jù),甚至在多個數(shù)據(jù)庫中也是如此。
但是,如果您希望更多地關(guān)注領(lǐng)域驅(qū)動的設(shè)計,ORM將在元數(shù)據(jù)和業(yè)務(wù)對象中封裝大部分底層模式和結(jié)構(gòu)。這種封裝可以使數(shù)據(jù)庫交互更像普通的Python代碼。大多數(shù)常見的應(yīng)用程序都適合以這種方式建模。它也可以是引入領(lǐng)域驅(qū)動設(shè)計的一種非常有效的方法,將SQLAlchemy引入到遺留應(yīng)用程序中,或者在整個應(yīng)用程序中散布原始SQL語句。微服務(wù)還受益于底層數(shù)據(jù)庫的抽象,允許開發(fā)人員只關(guān)注正在實現(xiàn)的流程。
但是,由于ORM是在SQLAlchemy Core之上構(gòu)建的,所以您可以使用它處理Oracle數(shù)據(jù)倉庫和Amazon Redshift等服務(wù)的能力,就像它與MySQL交互一樣。當(dāng)您需要組合業(yè)務(wù)對象和存儲的數(shù)據(jù)時,這對于ORM來說是一個極好的補充。
這里有一個快速清單,可以幫助你決定哪種選擇最適合你:
如果您使用的框架已經(jīng)內(nèi)建了ORM,但希望添加更強大的報表,請使用Core。
如果您希望以更以模式為中心的視圖(如SQL中使用的)查看數(shù)據(jù),請使用Core。
如果您有不需要業(yè)務(wù)對象的數(shù)據(jù),請使用Core。
如果您將數(shù)據(jù)視為業(yè)務(wù)對象,請使用ORM。
如果您正在構(gòu)建一個快速原型,請使用ORM。
如果您的需求組合確實可以利用業(yè)務(wù)對象和其他與問題領(lǐng)域無關(guān)的數(shù)據(jù),請同時使用它們!
現(xiàn)在,您已經(jīng)了解了SQLAlchemy的結(jié)構(gòu)以及Core和ORM之間的區(qū)別,我們已經(jīng)準(zhǔn)備好安裝并開始使用SQLAlchemy來連接數(shù)據(jù)庫。
SQLAlchemy的安裝
默認(rèn)情況下,SQLAlchemy將支持SQLite3,不需要額外的驅(qū)動程序;但是,需要一個使用標(biāo)準(zhǔn)Python DBAPI (PEP-249)規(guī)范的附加數(shù)據(jù)庫驅(qū)動程序來連接到其他數(shù)據(jù)庫。這些DBAPI為每個數(shù)據(jù)庫服務(wù)器使用的dialect提供了基礎(chǔ),并且通常支持在不同數(shù)據(jù)庫服務(wù)器和版本中看到的獨特特性。雖然許多數(shù)據(jù)庫可以使用多個dbapi,但是下面的說明主要針對最常見的數(shù)據(jù)庫:
PostgreSQL
Psycopg2提供了對PostgreSQL版本和特性的廣泛支持,可以與pip install Psycopg2一起安裝。
MySQL
PyMySQL是我用來連接MySQL數(shù)據(jù)庫服務(wù)器的首選Python庫。它可以與pip安裝pymysql一起安裝。SQLAlchemy中的MySQL支持要求MySQL版本4.1或更高,這是由于該版本之前密碼的工作方式。此外,如果特定的語句類型僅在MySQL的某個版本中可用,SQLAlchemy不提供在語句不可用的MySQL版本上使用這些語句的方法。如果SQLAlchemy中的某個組件或函數(shù)在您的環(huán)境中不起作用,那么檢查MySQL文檔是很重要的。
其他類型
SQLAlchemy還可以與Drizzle、Firebird、Oracle、Sybase和Microsoft SQL Server一起使用。該社區(qū)還為許多其他數(shù)據(jù)庫提供了外部dialect,如IBM DB2、Informix、Amazon Redshift、EXASolution、SAP SQL Anywhere、Monet等。
現(xiàn)在可以安裝SQLAlchemy
pip install -U sqlalchemy
檢查安裝結(jié)果:目前最新的發(fā)行版本是1.2.15,
>>> import sqlalchemy
>>> sqlalchemy.__version__
'1.2.15'
>>>
連接一個數(shù)據(jù)庫
要連接到數(shù)據(jù)庫,我們需要創(chuàng)建一個SQLAlchemy引擎。SQLAlchemy引擎創(chuàng)建到數(shù)據(jù)庫的公共接口來執(zhí)行SQL語句。它通過包裝數(shù)據(jù)庫連接池和dialect來實現(xiàn)這一點,這些連接池和dialect可以協(xié)同工作,提供對后端數(shù)據(jù)庫的統(tǒng)一訪問。這使我們的Python代碼不必?fù)?dān)心數(shù)據(jù)庫或dbapi之間的差異。
SQLAlchemy提供了一個函數(shù)來為我們創(chuàng)建一個引擎,該引擎提供了一個連接字符串和一些額外的關(guān)鍵字參數(shù)。連接字符串是一種特殊格式的字符串,它提供:
數(shù)據(jù)庫類型(Postgres, MySQL等)
除非數(shù)據(jù)庫類型是默認(rèn)的(Psycopg2、PyMySQL等),否則使用dialect。
可選身份驗證細節(jié)(用戶名和密碼)
數(shù)據(jù)庫的位置(數(shù)據(jù)庫服務(wù)器的文件或主機名)
可選的數(shù)據(jù)庫服務(wù)器端口,不指定則根據(jù)所選數(shù)據(jù)庫類型連接其常規(guī)的默認(rèn)端口
可選的數(shù)據(jù)庫名稱
SQLite數(shù)據(jù)庫連接字符串讓我們表示特定的文件或存儲位置。示例P-1定義了一個名為cookies的SQLite數(shù)據(jù)庫文件。db通過第二行中的相對路徑存儲在當(dāng)前目錄中,第三行是內(nèi)存中的數(shù)據(jù)庫,第四行(Unix)和第五行(Windows)是文件的完整路徑。在Windows上,連接字符串看起來像engine4;除非您使用原始字符串(r”),否則需要使用\進行適當(dāng)?shù)淖址D(zhuǎn)義。
示例P-1:創(chuàng)建一個連接SQLite的engine
from sqlalchemy import create_engine
engine = create_engine('sqlite:///cookies.db')
engine2 = create_engine('sqlite:///:memory:')
engine3 = create_engine('sqlite:////home/cookiemonster/cookies.db')
engine4 = create_engine('sqlite:///c:\\Users\\cookiemonster\\cookies.db')
提示:create_engine只是創(chuàng)建了一個engine實例,但是它并不會立即去連接數(shù)據(jù)庫,只有在需要連接數(shù)據(jù)庫的操作觸發(fā)后,engine才會去連接數(shù)據(jù)庫,譬如一個查詢操作。
讓我們?yōu)槊麨閙ydb的本地PostgreSQL數(shù)據(jù)庫創(chuàng)建一個引擎。我們首先從基本sqlalchemy包導(dǎo)入create_engine函數(shù)。接下來,我們將使用該函數(shù)構(gòu)造一個引擎實例。在示例P-2中,您會注意到我使用postgresql+psycopg2作為連接字符串的引擎和dialect組件,即使只使用postgres也可以工作。這是因為我更喜歡顯式而不是隱式,就像Python之禪推薦的那樣。
示例P-2:創(chuàng)建一個連接本地PostgreSQL的engine
from sqlalchemy import create_engine
engine = create_engine('postgresql+psycopg2://username:password@localhost:5432/mydb')
現(xiàn)在讓我們看一下遠程服務(wù)器上的MySQL數(shù)據(jù)庫。您將注意到,在示例P-3中,在連接字符串之后,我們有一個關(guān)鍵字參數(shù)pool_recycle,用于定義循環(huán)使用連接的頻率。
示例P-3:創(chuàng)建一個連接遠程MySQL數(shù)據(jù)庫的engine
from sqlalchemy import create_engine
engine = create_engine('mysql+pymysql://cookiemonster:chocolatechip@mysql01.monster.'
'internal/cookies', pool_recycle=3600)
注意:默認(rèn)情況下,MySQL會關(guān)閉空閑時間超過8小時的連接。要解決這個問題,在創(chuàng)建引擎時使用pool_recycle=3600,如示例P-3所示。
一些在創(chuàng)建engine時可選的參數(shù)如下:
-
echo這將記錄引擎處理的操作,如SQL語句及其參數(shù)。它默認(rèn)為false。
-
encoding這定義了SQLAlchemy使用的字符串編碼。它默認(rèn)為utf-8,大多數(shù)DBAPI默認(rèn)支持這種編碼。這并不定義后端數(shù)據(jù)庫本身使用的編碼類型。
-
isolation_level這指示SQLAlchemy使用特定的隔離級別。例如,帶有Psycopg2的PostgreSQL有READ COMMITTED、READ UNCOMMITTED、REPEATABLE READ、SERIALIZABLE和AUTOCOMMIT,默認(rèn)情況下是READ COMMITTED。PyMySQL具有相同的選項,默認(rèn)為InnoDB數(shù)據(jù)庫的可重復(fù)讀取。
注意:使用isolation_level關(guān)鍵字參數(shù)將為任何給定的DBAPI設(shè)置隔離級別。這與通過連接字符串中的鍵-值對(如支持該方法的Psycopg2)來實現(xiàn)相同。
-
pool_recyle這將定期回收或超時數(shù)據(jù)庫連接。由于前面提到的連接超時,這對于MySQL非常重要。它的默認(rèn)值是-1,這意味著沒有超時。
一旦初始化了引擎,就可以實際打開到數(shù)據(jù)庫的連接。這是通過調(diào)用引擎上的connect()方法實現(xiàn)的,如下所示:
from sqlalchemy import create_engine
engine = create_engine('mysql+pymysql://cookiemonster:chocolatechip'
'@mysql01.monster.internal/cookies', pool_recycle=3600)
connection = engine.connect()
現(xiàn)在我們已經(jīng)有了數(shù)據(jù)庫連接,可以開始使用SQLAlchemy Core或ORM。