django 多數(shù)據(jù)庫(kù)及分庫(kù)實(shí)現(xiàn)方式
定義及路由機(jī)制
定義
在settings里面的DATABASES是一個(gè)字典,用于定義需要的數(shù)據(jù)庫(kù),如下,一共定義了兩個(gè)數(shù)據(jù)庫(kù)。
DATABASES = { 'default': { 'NAME': 'app_data', 'ENGINE': 'django.db.backends.postgresql_psycopg2', 'USER': 'postgres_user', 'PASSWORD': 's3krit' }, 'user1': { 'NAME': 'user1_data', 'ENGINE': 'django.db.backends.mysql', 'USER': 'mysql_user', 'PASSWORD': 'priv4te' } 'user2': { 'NAME': 'user2_data', 'ENGINE': 'django.db.backends.mysql', 'USER': 'mysql_user', 'PASSWORD': 'priv4te' } }
那么什么時(shí)候調(diào)用default什么時(shí)候調(diào)用users數(shù)據(jù)庫(kù)呢,這就需要下面的路由。
路由注冊(cè)
class User1Router(object): """ A router to control all database operations on models in the auth application. """ def db_for_read(self, model, **hints): """ Attempts to read auth models go to auth_db. """ if model._meta.app_label == 'auth': return 'user1' return None def db_for_write(self, model, **hints): """ Attempts to write auth models go to auth_db. """ if model._meta.app_label == 'auth': return 'user1' return None def allow_relation(self, obj1, obj2, **hints): """ Allow relations if a model in the auth app is involved. """ if obj1._meta.app_label == 'auth' or \ obj2._meta.app_label == 'auth': return True return None def allow_syncdb(self, db, model): """ Make sure the auth app only appears in the 'auth_db' database. """ if db == 'auth_db': return model._meta.app_label == 'auth' elif model._meta.app_label == 'user1': return False return None class User2Router(object): """ A router to control all database operations on models in the auth application. """ def db_for_read(self, model, **hints): """ Attempts to read auth models go to auth_db. """ if model._meta.app_label == 'auth2': return 'user2' return None def db_for_write(self, model, **hints): """ Attempts to write auth models go to auth_db. """ if model._meta.app_label == 'auth2': return 'user2' return None def allow_relation(self, obj1, obj2, **hints): """ Allow relations if a model in the auth app is involved. """ if obj1._meta.app_label == 'auth' or \ obj2._meta.app_label == 'auth': return True return None def allow_syncdb(self, db, model): """ Make sure the auth app only appears in the 'auth_db' database. """ if db == 'auth_db': return model._meta.app_label == 'auth2' elif model._meta.app_label == 'user2': return False return None
User1Router的路由邏輯是,如果model所屬的app是auth的話,就使用user1數(shù)據(jù)庫(kù),否則就使用其他的;User2Router的邏輯類似。
如何注冊(cè)路由
光定義路由程序無法調(diào)用到,還需要注冊(cè)到django中,在settings中定義
DATABASE_ROUTERS = ['path.to.User1Router' , 'path.to.User2Router']
path.to:是User1Router的完整python包路徑,所以,User1Router不一定要在settings中實(shí)現(xiàn),可以在任何地方。
路由機(jī)制
那么django是如何選擇其中一個(gè)路由的呢?
1. django按照注冊(cè)的順序輪詢DATABASE_ROUTERS,所以首先驗(yàn)證User1Router是否返回了非空字符串,如果是,則使用User1Router;如果不是則接著驗(yàn)證后面的Router;
2. 同樣驗(yàn)證User2Router,如果User2Router返回了非空字符串,則使用User2Router;如果不是則使用default數(shù)據(jù)庫(kù);
3. 所以可以看出,路由注冊(cè)的順序是會(huì)影響最后的結(jié)果的,注冊(cè)在前面的路由會(huì)優(yōu)先被使用;
自動(dòng)路由和手動(dòng)路由
上面定義的Router是自動(dòng)路由,意思是django會(huì)自動(dòng)輪詢所注冊(cè)的路由器,某個(gè)model會(huì)保存在哪個(gè)數(shù)據(jù)庫(kù),是django通過注冊(cè)的Router自動(dòng)獲得的,在編碼中你不需要指定;
手動(dòng)路由,則是你可以在編碼中指定某個(gè)model要保存到哪個(gè)數(shù)據(jù)庫(kù)。
而且手動(dòng)路由也有性能方面的優(yōu)點(diǎn),如果定義了很多個(gè)數(shù)據(jù)庫(kù),每次保存或者讀取model都要把輪詢一遍路由列表,顯然效率有些低,如果程序邏輯清楚的知道當(dāng)前的代碼應(yīng)該連接哪個(gè)數(shù)據(jù)庫(kù),顯示指定的方式顯然效率更高。
手動(dòng)路由
查詢
使用using函數(shù),參數(shù)就是要查詢的數(shù)據(jù)庫(kù)
User.objects.using('user1').all()
保存或者更新
使用save的using參數(shù),值就是要使用的數(shù)據(jù)庫(kù)
>>> my_object.save(using='user1')
刪除
使用delete的using參數(shù)
>>> user_obj.delete(using='user1')
分庫(kù)技術(shù)
下面緊緊介紹分庫(kù)的思路。
垂直分庫(kù)
即一個(gè)app對(duì)應(yīng)一個(gè)數(shù)據(jù)庫(kù),上面自動(dòng)路由的例子就是一個(gè)垂直分庫(kù)的例子,auth1使用user1數(shù)據(jù)庫(kù),auth2使用user2數(shù)據(jù)庫(kù)。當(dāng)然也可以使用手動(dòng)路由。
水平分庫(kù)
水平分庫(kù)建議使用手動(dòng)路由,因?yàn)槊總€(gè)model的分庫(kù)機(jī)制可能都不一樣,自動(dòng)路由實(shí)現(xiàn)起來有些麻煩會(huì)造成性能不高,而手動(dòng)路由,每個(gè)model根據(jù)自己的規(guī)則來獲得不同的數(shù)據(jù)庫(kù)。
補(bǔ)充知識(shí):Django實(shí)現(xiàn)數(shù)據(jù)庫(kù)讀寫分離、一主多從、分庫(kù)
讀寫分離
在工程中,通常需要實(shí)現(xiàn)mysql讀寫分離。在Django中需要支持讀寫分離的話,只需要很簡(jiǎn)單的幾步就可以了。
首先,配置讀庫(kù)和寫庫(kù)。
在django項(xiàng)目的settings.py中,配置讀庫(kù)和寫庫(kù)。
DATABASES = { 'default': { 'ENGINE': 'django.db.backends.mysql', 'NAME': 'WIPS', 'USER': 'mysql', 'PASSWORD': '360tianxun#^)Sec', 'HOST': '', 'PORT': '', }, 'slave': { 'ENGINE': 'django.db.backends.mysql', 'NAME': 'TEST', 'USER': 'mysql', 'PASSWORD': '360tianxun#^)Sec', 'HOST': '', 'PORT': '', }, }
接下來,需要?jiǎng)?chuàng)建數(shù)據(jù)庫(kù)的路由分發(fā)類。
可以在appname/utils下創(chuàng)建一個(gè)db_router.py文件,在文件中定義db_router類。類中實(shí)現(xiàn)讀庫(kù)寫庫(kù)的選擇。
class DBRouter(object): def db_for_read(self, model, **hints): return "slave" def db_for_write(self, model, **hints): return "default" def allow_relation(self, obj1, obj2, **hints): return True
最后,在settings.py中添加路由配置。
DATABASE_ROUTERS = ['appname.utils.db_router.DBRouter' ]
重新啟動(dòng)Django就完成了。
這里需要注意的是,Django只完成了讀寫分離,但mysql主庫(kù)、從庫(kù)的同步操作并不歸django負(fù)責(zé),依然需要mysql實(shí)現(xiàn)。
一主多從
一主多從的方案在實(shí)際應(yīng)用中是更常見的配置。在上面配置的基礎(chǔ)上,只需要修改幾個(gè)地方,就可以實(shí)現(xiàn)一主多從了。
首先,修改settings.py,增加全部從庫(kù)的設(shè)置。
其次,修改db_router類中db_for_read(),下面是隨機(jī)選取讀庫(kù)的例子。也可以根據(jù)實(shí)際的需要,選取不同的調(diào)度算法。
class DBRouter(object): def db_for_read(self, model, **hints): import random return random.choice(['slave', 'slave2', 'slave3'])
分庫(kù)
當(dāng)需要不同的app使用不同的庫(kù)時(shí),可以利用model中的app_label來實(shí)現(xiàn)db的路由。
class DBRouter(object): def db_for_read(self, model, **hints): if model._meta.app_label == 'app01': import random return random.choice(['app01_slave1', 'app01_slave2', 'app01_slave3']) if model._meta.app_label == 'app02': return "app02_slave"
按照上面的操作就很容易實(shí)現(xiàn)mysql的讀寫分離、一主多從和分庫(kù)了。但這個(gè)方法只建議用在小項(xiàng)目上。
以上這篇django 多數(shù)據(jù)庫(kù)及分庫(kù)實(shí)現(xiàn)方式就是小編分享給大家的全部?jī)?nèi)容了,希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
- 詳解多線程Django程序耗盡數(shù)據(jù)庫(kù)連接的問題
- Django使用多數(shù)據(jù)庫(kù)的方法
- Django中數(shù)據(jù)庫(kù)的數(shù)據(jù)關(guān)系:一對(duì)一,一對(duì)多,多對(duì)多
- django 多數(shù)據(jù)庫(kù)配置教程
- Django app配置多個(gè)數(shù)據(jù)庫(kù)代碼實(shí)例
- Django多數(shù)據(jù)庫(kù)配置及逆向生成model教程
- django 鏈接多個(gè)數(shù)據(jù)庫(kù) 并使用原生sql實(shí)現(xiàn)
- Django多數(shù)據(jù)庫(kù)的實(shí)現(xiàn)過程詳解
- Django多數(shù)據(jù)庫(kù)聯(lián)用實(shí)現(xiàn)方法解析
- django使用多個(gè)數(shù)據(jù)庫(kù)的方法實(shí)例
相關(guān)文章
python中創(chuàng)建以及刪除虛擬環(huán)境的幾種方法總結(jié)
在Python?中創(chuàng)建虛擬環(huán)境非常容易,但是刪除虛擬環(huán)境可能會(huì)有一些挑戰(zhàn),這篇文章主要給大家介紹了關(guān)于python中創(chuàng)建以及刪除虛擬環(huán)境的幾種方法,需要的朋友可以參考下2024-03-03Flask-Docs自動(dòng)生成Api文檔安裝使用教程
這篇文章主要為大家介紹了Flask-Docs自動(dòng)生成Api文檔安裝使用教程,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-10-10python -m pip install 和 pip in
python -m pip install <package> 使用了 -m 參數(shù)來確保以 Python 模塊的形式運(yùn)行 pip,適用于確保在不同的環(huán)境中正確使用 pip,這篇文章主要介紹了python -m pip install 和 pip install 的區(qū)別,需要的朋友可以參考下2023-07-07Python實(shí)現(xiàn)點(diǎn)云投影到平面顯示
今天小編就為大家分享一篇Python實(shí)現(xiàn)點(diǎn)云投影到平面顯示,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2020-01-01Numpy array數(shù)據(jù)的增、刪、改、查實(shí)例
今天小編就為大家分享一篇Numpy array數(shù)據(jù)的增、刪、改、查實(shí)例,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2018-06-06Django異步任務(wù)線程池實(shí)現(xiàn)原理
這篇文章主要介紹了Django異步任務(wù)線程池實(shí)現(xiàn)原理,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2019-12-12Python使用Srapy框架爬蟲模擬登陸并抓取知乎內(nèi)容
這里我們來看如何通過Python使用Srapy框架爬蟲模擬登陸并抓取知乎內(nèi)容的實(shí)例,要實(shí)現(xiàn)持續(xù)的爬取需要利用到cookie的保存,我們首先還是來回顧一下cookie的相關(guān)知識(shí)點(diǎn):2016-07-07python實(shí)現(xiàn)學(xué)生信息管理系統(tǒng)源碼
這篇文章主要為大家詳細(xì)介紹了python實(shí)現(xiàn)學(xué)生信息管理系統(tǒng)源碼,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-02-02