django 多数据库及分库实现方式
定义及路由机制
定义
在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 多数据库及分库实现方式就是小编分享给大家的全部内容了,希望能给大家一个参考。
- Webpack 实用技巧高效实战
- oracle表空间不足相关问题解决办法
- 手工打造分布式爬虫
- (64) 常见文件类型处理: 属性文件/CSV/EXCEL/HTML/压缩文件 / 计算机程序的思维逻辑
- org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter与org.apache.struts2.dispatcher.
- Python协程演进过程
- Android TV开发简介
- (59) 文件和目录操作 / 计算机程序的思维逻辑
- Rdseed与SAC的安装
- Python爬虫大战京东商城
- (77) 异步任务执行服务 / 计算机程序的思维逻辑
- Unity Android Plugin开发指南
- Python还能做这个?真的好棒棒耶!
- java中Comparator的用法
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- 太实用了!自己动手写软件——SSH、FTP和SQL server的密码破解
- Kaggle Tweet Sentiment Extraction 第七名复盘
- 【翻译】.NET 5中的性能改进
- 腾讯云实时语音识别-iOS SDK
- JointPoint用法及与ProceedingJoinPoint 的关系
- Spring中的异步请求、异步调用及demo测试
- 以太坊交易签名解析源码解读
- 比较NaN和数字
- GO 的方法集
- 轻松应对并发问题,简易的火车票售票系统,第一步 —业务分析
- 【Spark Operator】核数设置Cores/Cores Limit/Cores Request,你搞清楚没有?
- 【Ceph RGW】radosgw_usage_exporter监控用户使用量
- 【Goland】#{key}=#{value},字符串被格式化了?
- Variable变量
- 案例:OGG目标端进程ABENDED处理