摘要:數(shù)據(jù)庫(kù)關(guān)系數(shù)據(jù)庫(kù)將數(shù)據(jù)保存在表中來模擬應(yīng)用程序中不同的實(shí)體。這些行之間的連接稱作關(guān)系,也是關(guān)系數(shù)據(jù)庫(kù)模型的基礎(chǔ)。就像這個(gè)示例中看到的那樣,關(guān)系數(shù)據(jù)庫(kù)存儲(chǔ)數(shù)據(jù)高效且避免重復(fù)。最好的例子就是,支持一組關(guān)系數(shù)據(jù)庫(kù)引擎,包括流行的和。
數(shù)據(jù)庫(kù)就是有組織的存儲(chǔ)應(yīng)用程序數(shù)據(jù),然后查詢檢索指定需要的那部分。大部分web應(yīng)用程序都采用基于關(guān)系模型的數(shù)據(jù)庫(kù),也稱作結(jié)構(gòu)化查詢語(yǔ)言(SQL)數(shù)據(jù)庫(kù)。但是最近幾年面向文檔數(shù)據(jù)庫(kù)和鍵值數(shù)據(jù)庫(kù)(通常稱作NoSQL數(shù)據(jù)庫(kù)),成為非常流行的替代者。個(gè)人推薦《七周七數(shù)據(jù)庫(kù)》這本書,它對(duì)各種類型的數(shù)據(jù)庫(kù)、應(yīng)用場(chǎng)景和多種不同類型數(shù)據(jù)庫(kù)配合使用有比較好的講解。
1、SQL數(shù)據(jù)庫(kù)關(guān)系數(shù)據(jù)庫(kù)將數(shù)據(jù)保存在表中來模擬應(yīng)用程序中不同的實(shí)體。例如,一個(gè)訂單管理應(yīng)用程序數(shù)據(jù)庫(kù)可能會(huì)有customers、products和orders表。
一個(gè)表有一個(gè)固定數(shù)量的列和一個(gè)可變的行數(shù)。列定義了數(shù)據(jù)表所代表的實(shí)體的屬性。例如,customers表會(huì)有name、address、phone等列。表中的每一行定義了由所有列的值組成的實(shí)際數(shù)據(jù)元素。
表有種特殊列稱作主鍵,它持有一個(gè)惟一的標(biāo)識(shí)符為表中存儲(chǔ)的每一行。表也可以有外鍵,用于引用其他表的主鍵。這些行之間的連接稱作關(guān)系,也是關(guān)系數(shù)據(jù)庫(kù)模型的基礎(chǔ)。
圖像5-1展示了存儲(chǔ)users和roles表的簡(jiǎn)單數(shù)據(jù)庫(kù)圖。連接兩個(gè)表的線代表兩個(gè)表之間的關(guān)系。
圖像5-1. 關(guān)系數(shù)據(jù)庫(kù)示例
在這個(gè)數(shù)據(jù)庫(kù)表中,roles表存儲(chǔ)了一組所有可能的用戶角色,每一個(gè)都被定義為唯一id值——也是表的主鍵。users表包含一組用戶,同樣每一個(gè)都有唯一id值。除了主鍵id,roles表還有name列,而users表還有username和password列。在users表中的role_id列是一個(gè)引用role表中id列的外鍵,以這種方式確立分配給每個(gè)用戶的角色。
就像這個(gè)示例中看到的那樣,關(guān)系數(shù)據(jù)庫(kù)存儲(chǔ)數(shù)據(jù)高效且避免重復(fù)。重命名用戶角色在這個(gè)數(shù)據(jù)庫(kù)中會(huì)變得異常簡(jiǎn)單,因?yàn)榻巧4嬖诙鄮У牡胤健.?dāng)roles表中的角色名發(fā)生改變,所有用戶持有的role_id引用的角色會(huì)立即看到這些變化。
而另一方面,將數(shù)據(jù)拆分到多個(gè)表中則會(huì)變得更加復(fù)雜。生成一組用戶及其角色會(huì)產(chǎn)生一個(gè)小問題,因?yàn)橛脩艉陀脩艚巧枰獜膬蓮埍碇凶x,且只有連接后才能一起出現(xiàn)。當(dāng)需要的時(shí)候關(guān)系數(shù)據(jù)庫(kù)引擎會(huì)提供支持來執(zhí)行兩個(gè)表的連接操作。
2、NoSQL數(shù)據(jù)庫(kù)與上一節(jié)描述相反的、非關(guān)系模型的數(shù)據(jù)庫(kù)被統(tǒng)稱為NoSQL數(shù)據(jù)庫(kù)。NoSQL數(shù)據(jù)庫(kù)常見的組織方式是使用collections代替表、documents代替記錄。NoSQL數(shù)據(jù)庫(kù)的設(shè)計(jì)方式使得連接會(huì)很復(fù)雜,所以大部分都不支持這個(gè)操作。圖像5-1如果用NoSQL數(shù)據(jù)庫(kù)結(jié)構(gòu)來表達(dá)則是這樣的:列出用戶及他們的角色,需要應(yīng)用程序自己通過讀取每個(gè)用戶的role_id字段去執(zhí)行連接操作,然后查找roles表。
圖像5-2展示了更接近NoSQL數(shù)據(jù)庫(kù)的設(shè)計(jì)思想。這個(gè)操作運(yùn)用了一個(gè)被稱為反模式的思想,減少了表的數(shù)量卻增加了重復(fù)數(shù)據(jù)。
圖像5-2. NoSQL數(shù)據(jù)庫(kù)示例
這種結(jié)構(gòu)的數(shù)據(jù)庫(kù)為每個(gè)用戶顯式的存儲(chǔ)用戶角色名。重命名角色名絕對(duì)是一項(xiàng)昂貴的操作,可能需要更新大量的文檔。
但對(duì)于NoSQL數(shù)據(jù)庫(kù)這并不都是壞消息。雖然有重復(fù)的數(shù)據(jù),但是查詢速度快,因?yàn)椴恍枰B接,可以直接列出用戶和他們的角色。
3、SQL還是NoSQLSQL數(shù)據(jù)庫(kù)擅長(zhǎng)以高效、緊湊的形式存儲(chǔ)結(jié)構(gòu)化數(shù)據(jù)。這些數(shù)據(jù)庫(kù)竭盡全力保持一致性。NoSQL數(shù)據(jù)庫(kù)會(huì)放低一些一致性要求,因此在性能上有更大的優(yōu)勢(shì)。
全面分析和比較數(shù)據(jù)庫(kù)類型已經(jīng)超出了本教程的范圍。對(duì)于中小型應(yīng)用程序SQL數(shù)據(jù)庫(kù)和NoSQL數(shù)據(jù)庫(kù)完全可以勝任,且性能幾乎差不多。
4、Python數(shù)據(jù)庫(kù)框架Python有大部分的數(shù)據(jù)庫(kù)引擎包,包括開源的和商業(yè)的。Flask在可使用的數(shù)據(jù)庫(kù)包上沒有限制,所以你可以使用MySQL、Postgres、SQLite、Redis、MongoDB或者CouchDB中你喜歡的任何一個(gè)。
如果這些還不夠,也有大量的數(shù)據(jù)庫(kù)抽象層包,如SQLAlchemy或MongoEngine讓你像操作常規(guī)Python對(duì)象那樣,而不是數(shù)據(jù)庫(kù)實(shí)體表、文檔或查詢語(yǔ)句。
在選擇數(shù)據(jù)庫(kù)框架的時(shí)候需要評(píng)估許多因素:
易用性
如果直接比較數(shù)據(jù)庫(kù)引擎和數(shù)據(jù)庫(kù)抽象層,第二者明顯勝出。抽象層又稱作對(duì)象關(guān)系映射(ORM)或?qū)ο笪臋n映射(ODM),提供從高級(jí)面向?qū)ο蟛僮鞯降讓訑?shù)據(jù)庫(kù)指令的透明轉(zhuǎn)換。
性能
ORM和ODM的轉(zhuǎn)化需要從對(duì)象域轉(zhuǎn)化為數(shù)據(jù)庫(kù)域,所以會(huì)有一些開銷。大多數(shù)情況下,性能損耗是微不足道的,但總有例外。一般來說,ORM和ODM獲得的生產(chǎn)力遠(yuǎn)遠(yuǎn)超過了性能下降的那部分,所以這不是一個(gè)有效的論點(diǎn)來完全拋棄ORM和ODM。應(yīng)該關(guān)心的是選擇怎樣的數(shù)據(jù)庫(kù)抽象層,提供可訪問底層數(shù)據(jù)庫(kù)中特定操作,就像本地?cái)?shù)據(jù)庫(kù)指令那樣實(shí)現(xiàn)的抽象層最佳。
可移植性
數(shù)據(jù)庫(kù)的選擇必須考慮開發(fā)和生產(chǎn)平臺(tái)。例如,如果你計(jì)劃在云主機(jī)上托管應(yīng)用程序,那么你應(yīng)該找出提供該服務(wù)的數(shù)據(jù)庫(kù)。
另一方面ORM和ODM的可移植性不錯(cuò)。盡管一些框架只為單個(gè)數(shù)據(jù)庫(kù)引擎提供抽象層,有些抽象層更高級(jí),可以選擇哪種數(shù)據(jù)庫(kù)引擎且訪問使用的是同一個(gè)面向?qū)ο蟮慕涌凇W詈玫睦泳褪荢QLAlchemy ORM,支持一組關(guān)系數(shù)據(jù)庫(kù)引擎,包括流行的MySQL、Postgres和SQLite。
Flask集成
選擇一個(gè)集成了Flask的框架并不是必須的,但是可以不用自己寫集成代碼。Flask集成可以簡(jiǎn)化配置和操作,所以應(yīng)該優(yōu)先使用專門設(shè)計(jì)的Flask擴(kuò)展包。
基于這些目的,F(xiàn)lask-SQLAlchemy將是本書示例中應(yīng)該選擇的數(shù)據(jù)庫(kù)框架,它對(duì)SQLAlchemy進(jìn)行了封裝。
5、使用Flask-SQLAlchemy管理數(shù)據(jù)庫(kù)Flask-SQLAlchemy是一個(gè)Flask擴(kuò)展,它簡(jiǎn)化了在Flask應(yīng)用程序中對(duì)SQLAlchemy的使用。SQLAlchemy是一個(gè)強(qiáng)大的關(guān)系數(shù)據(jù)庫(kù)框架,支持一些數(shù)據(jù)庫(kù)后端。提供高級(jí)的ORM和底層訪問數(shù)據(jù)庫(kù)的本地SQL功能。
和其他擴(kuò)展一樣,通過pip安裝Flask-SQLAlchemy:
(venv) $ pip install flask-sqlalchemy
在Flask-SQLAlchemy,數(shù)據(jù)庫(kù)被指定為URL。表格5-1列出三個(gè)最受歡迎的數(shù)據(jù)庫(kù)引擎url的格式。