django 多数据库及分库实现方式


Posted in Python onApril 01, 2020

定义及路由机制

定义

在settings里面的DATABASES是一个字典,用于定义需要的数据库,如下,一共定义了两个数据库。

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'
 }
}

那么什么时候调用default什么时候调用users数据库呢,这就需要下面的路由。

路由注册

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数据库,否则就使用其他的;User2Router的逻辑类似。

如何注册路由

光定义路由程序无法调用到,还需要注册到django中,在settings中定义

DATABASE_ROUTERS = ['path.to.User1Router' , 'path.to.User2Router']

path.to:是User1Router的完整python包路径,所以,User1Router不一定要在settings中实现,可以在任何地方。

路由机制

那么django是如何选择其中一个路由的呢?

1. django按照注册的顺序轮询DATABASE_ROUTERS,所以首先验证User1Router是否返回了非空字符串,如果是,则使用User1Router;如果不是则接着验证后面的Router;

2. 同样验证User2Router,如果User2Router返回了非空字符串,则使用User2Router;如果不是则使用default数据库;

3. 所以可以看出,路由注册的顺序是会影响最后的结果的,注册在前面的路由会优先被使用;

自动路由和手动路由

上面定义的Router是自动路由,意思是django会自动轮询所注册的路由器,某个model会保存在哪个数据库,是django通过注册的Router自动获得的,在编码中你不需要指定;

手动路由,则是你可以在编码中指定某个model要保存到哪个数据库。

而且手动路由也有性能方面的优点,如果定义了很多个数据库,每次保存或者读取model都要把轮询一遍路由列表,显然效率有些低,如果程序逻辑清楚的知道当前的代码应该连接哪个数据库,显示指定的方式显然效率更高。

手动路由

查询

使用using函数,参数就是要查询的数据库

User.objects.using('user1').all()

保存或者更新

使用save的using参数,值就是要使用的数据库

>>> my_object.save(using='user1')

删除

使用delete的using参数

>>> user_obj.delete(using='user1')

分库技术

下面紧紧介绍分库的思路。

垂直分库

即一个app对应一个数据库,上面自动路由的例子就是一个垂直分库的例子,auth1使用user1数据库,auth2使用user2数据库。当然也可以使用手动路由。

水平分库

水平分库建议使用手动路由,因为每个model的分库机制可能都不一样,自动路由实现起来有些麻烦会造成性能不高,而手动路由,每个model根据自己的规则来获得不同的数据库。

补充知识:Django实现数据库读写分离、一主多从、分库

读写分离

在工程中,通常需要实现mysql读写分离。在Django中需要支持读写分离的话,只需要很简单的几步就可以了。

首先,配置读库和写库。

在django项目的settings.py中,配置读库和写库。

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': '',   
 },
}

接下来,需要创建数据库的路由分发类。

可以在appname/utils下创建一个db_router.py文件,在文件中定义db_router类。类中实现读库写库的选择。

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' ]

重新启动Django就完成了。

这里需要注意的是,Django只完成了读写分离,但mysql主库、从库的同步操作并不归django负责,依然需要mysql实现。

一主多从

一主多从的方案在实际应用中是更常见的配置。在上面配置的基础上,只需要修改几个地方,就可以实现一主多从了。

首先,修改settings.py,增加全部从库的设置。

其次,修改db_router类中db_for_read(),下面是随机选取读库的例子。也可以根据实际的需要,选取不同的调度算法。

class DBRouter(object):
 def db_for_read(self, model, **hints):
 import random
 return random.choice(['slave', 'slave2', 'slave3'])

分库

当需要不同的app使用不同的库时,可以利用model中的app_label来实现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"

按照上面的操作就很容易实现mysql的读写分离、一主多从和分库了。但这个方法只建议用在小项目上。

以上这篇django 多数据库及分库实现方式就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持三水点靠木。

Python 相关文章推荐
Python读取mp3中ID3信息的方法
Mar 05 Python
基于scrapy实现的简单蜘蛛采集程序
Apr 17 Python
Python复制文件操作实例详解
Nov 10 Python
Python 查看文件的编码格式方法
Dec 21 Python
Python视频爬虫实现下载头条视频功能示例
May 07 Python
浅谈python编译pyc工程--导包问题解决
Mar 20 Python
Python函数装饰器原理与用法详解
Aug 16 Python
如何在mac环境中用python处理protobuf
Dec 25 Python
使用Bazel编译TensorBoard教程
Feb 15 Python
基于django micro搭建网站实现加水印功能
May 22 Python
Python存储读取HDF5文件代码解析
Nov 25 Python
Python连续赋值需要注意的一些问题
Jun 03 Python
详解使用python3.7配置开发钉钉群自定义机器人(2020年新版攻略)
Apr 01 #Python
Django更新models数据库结构步骤
Apr 01 #Python
pycharm工具连接mysql数据库失败问题
Apr 01 #Python
利用Python自动化操作AutoCAD的实现
Apr 01 #Python
python使用信号量动态更新配置文件的操作
Apr 01 #Python
python和pywin32实现窗口查找、遍历和点击的示例代码
Apr 01 #Python
python自动脚本的pyautogui入门学习
Apr 01 #Python
You might like
PHP创建XML接口示例
2019/07/04 PHP
JavaScript 组件之旅(三):用 Ant 构建组件
2009/10/28 Javascript
jQuery maxlength文本字数限制插件
2010/04/16 Javascript
jquery offset函数应用实例
2012/11/14 Javascript
javascript实现tabs选项卡切换效果(自写原生js)
2013/03/19 Javascript
JS完成代码前最好对其做5件事
2013/04/07 Javascript
js和php如何获取当前url的内容
2013/09/22 Javascript
node.js中的fs.unlinkSync方法使用说明
2014/12/15 Javascript
Vue2组件tree实现无限级树形菜单
2017/03/29 Javascript
深入理解vue中slot与slot-scope的具体使用
2018/01/26 Javascript
webpack4 处理CSS的方法示例
2018/09/03 Javascript
Vue页面切换和a链接的本质区别详解
2019/11/12 Javascript
vue 实现websocket发送消息并实时接收消息
2019/12/09 Javascript
[01:02:03]2014 DOTA2华西杯精英邀请赛 5 24 NewBee VS VG
2014/05/26 DOTA
[00:35]DOTA2上海特级锦标赛 Newbee战队宣传片
2016/03/03 DOTA
深入解析Python中的lambda表达式的用法
2015/08/28 Python
Python+Pika+RabbitMQ环境部署及实现工作队列的实例教程
2016/06/29 Python
微信跳一跳python代码实现
2018/01/05 Python
Python实现迭代时使用索引的方法示例
2018/06/05 Python
python使用xlrd和xlwt读写Excel文件的实例代码
2018/09/05 Python
详解Python 爬取13个旅游城市,告诉你五一大家最爱去哪玩?
2019/05/07 Python
使用Python做垃圾分类的原理及实例代码附源码
2019/07/02 Python
Python如何使用函数做字典的值
2019/11/30 Python
Python selenium抓取虎牙短视频代码实例
2020/03/02 Python
用 python 进行微信好友信息分析
2020/11/28 Python
Python 求向量的余弦值操作
2021/03/04 Python
CSS3下的渐变文字效果实现示例
2018/03/02 HTML / CSS
HTML5拖放效果的实现代码
2016/11/17 HTML / CSS
日本面向世界,国际级的免税在线购物商城:DOKODEMO
2017/02/01 全球购物
全球最大的户外用品零售商之一:The House
2018/06/12 全球购物
社区优秀志愿者先进事迹
2014/05/09 职场文书
市场营销专业应届生自荐信
2014/06/19 职场文书
审计局2014法制宣传日活动总结
2014/11/01 职场文书
2014年电话客服工作总结
2014/12/09 职场文书
关于调整工作时间的通知
2015/04/24 职场文书
父亲去世追悼词
2015/06/23 职场文书