(转)Django配置数据库读写分离
转:https://blog.csdn.net/Ayhan_huang/article/details/78784486
转:http://www.cnblogs.com/dreamer-fish/p/5469141.html
目录
简述
对网站的数据库作读写分离(Read/Write Splitting)可以提高性能,在Django中对此提供了支持,下面我们来简单看一下。注意,还需要运维人员作数据库的读写分离和数据同步。
配置数据库
我们知道在Django项目的settings中,可以配置数据库,除了默认的数据库,我在下面又加了一个db2。因为是演示,我这里用的是默认的SQLite,如果希望用MySQL,看这里 。
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
},
'db2': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': os.path.join(BASE_DIR, 'db2.sqlite3'),
创建models并执行数据库迁移
这里我简单创建一张产品表
from django.db import models class Products(models.Model):
"""产品表"""
prod_name = models.CharField(max_length=30)
prod_price = models.DecimalField(max_digits=6, decimal_places=2)
创建完成后,执行数据库迁移操作:
python manage.py makemigrations # 在migrations文件夹下生成记录,迁移前检查
python manage.py migrate # 创建表
#
python manage.py migrate --database default
python manage.py migrate --database db2 # 根据settings里的名称逐个迁移
在migrations文件夹下生成记录,并在迁移前检查是否有问题,默认值检查defualt数据库,但是可以在后面的数据库路由类(Router)中通过allow_migrate()方法来指定是否检查其它的数据库。
其实第二步迁移默认有参数python manage.py migrate --database default ,在默认数据库上创建表。因此完成以上迁移后,执行python manage.py --database db2,再迁移一次,就可以在db2上创建相同的表。这样在项目根目录下,就有了两个表结构一样的数据库,分别是db.sqlite3和db2.sqlite3。
读写分离
手动读写分离
在使用数据库时,通过.using(db_name)来手动指定要使用的数据库
from django.shortcuts import HttpResponse
from . import models def write(request):
models.Products.objects.using('default').create(prod_name='熊猫公仔', prod_price=12.99)
return HttpResponse('写入成功') def read(request):
obj = models.Products.objects.filter(id=1).using('db2').first()
return HttpResponse(obj.prod_name)
自动读写分离
通过配置数据库路由,来自动实现,这样就不需要每次读写都手动指定数据库了。数据库路由中提供了四个方法。这里这里主要用其中的两个:def db_for_read()决定读操作的数据库,def db_for_write()决定写操作的数据库。
定义Router类
新建myrouter.py脚本,定义Router类:
class Router:
def db_for_read(self, model, **hints):
return 'db2' def db_for_write(self, model, **hints):
return 'default'
配置Router
settings.py中指定DATABASE_ROUTERS
DATABASE_ROUTERS = ['myrouter.Router',]
可以指定多个数据库路由,比如对于读操作,Django将会循环所有路由中的db_for_read()方法,直到其中一个有返回值,然后使用这个数据库进行当前操作。
一主多从方案
网站的读的性能通常更重要,因此,可以多配置几个数据库,并在读取时,随机选取,比如:
class Router:
def db_for_read(self, model, **hints):
"""
读取时随机选择一个数据库
"""
import random
return random.choice(['db2', 'db3', 'db4']) def db_for_write(self, model, **hints):
"""
写入时选择主库
"""
return 'default'
分库分表
在大型web项目中,常常会创建多个app来处理不同的业务,如果希望实现app之间的数据库分离,比如app01走数据库db1,app02走数据库
class Router:
def db_for_read(self, model, **hints):
if model._meta.app_label == 'app01':
return 'db1'
if model._meta.app_label == 'app02':
return 'db2' def db_for_write(self, model, **hints):
if model._meta.app_label == 'app01':
return 'db1'
if model._meta.app_label == 'app02':
return 'db2'
例子
别人的例子
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',
'NAME': 'testly',
'USER': 'root',
'PASSWORD': '',
'HOST':'192.168.1.1',
'PORT':'',
},
'hvdb':{ #配置第二个数据库节点名称
'ENGINE': 'django.db.backends.mysql',
'NAME': 'testdjango', #第二个数据库的名称
'USER': 'root',
'PASSWORD': '',
'HOST':'192.168.1.1',
'PORT':'',
}
} DATABASE_ROUTERS = ['tt.db_router.app02Router'] #tt为当前项目名称,db_router为上一步编写的db_router.py文件,app02Router为Router
#DATABASE_ROUTERS = ['tt.db_router.app02Router','tt.db_router.app01Router'] #如果定义了多个Router,在此就需要分别指定。注意:这个是有顺序的(先匹配上的规则,就先生效)
settings.py
# -*- coding: UTF-8 -*-
class app02Router(object): #配置app02的路由,去连接hvdb数据库
"""
A router to control all database operations on models in the app02 application.
"""
def db_for_read(self, model, **hints):
"""
Attempts to read app02 models go to hvdb DB.
"""
if model._meta.app_label == 'app02': #app name(如果该app不存在,则无法同步成功)
return 'hvdb' #hvdb为settings中配置的database节点名称,并非db name。dbname为testdjango
return None def db_for_write(self, model, **hints):
"""
Attempts to write app02 models go to hvdb DB.
"""
if model._meta.app_label == 'app02':
return 'hvdb'
return None def allow_relation(self, obj1, obj2, **hints):
"""
Allow relations if a model in the app02 app is involved.
当 obj1 和 obj2 之间允许有关系时返回 True ,不允许时返回 False ,或者没有 意见时返回 None 。
"""
if obj1._meta.app_label == 'app02' or \
obj2._meta.app_label == 'app02':
return True
return None def allow_migrate(self, db, model):
"""
Make sure the app02 app only appears in the hvdb database.
"""
if db == 'hvdb':
return model._meta.app_label == 'app02'
elif model._meta.app_label == 'app02':
return False def allow_syncdb(self, db, model): #决定 model 是否可以和 db 为别名的数据库同步
if db == 'hvdb' or model._meta.app_label == "app02":
return False # we're not using syncdb on our hvdb database
else: # but all other models/databases are fine
return True
return None # class app01Router(object):
# """
# A router to control all database operations on models in the
# aew application.
# """
# def db_for_read(self, model, **hints):
# """
# Attempts to read aew models go to aew DB.
# """
# if model._meta.app_label == 'app01':
# return 'default'
# return None # def db_for_write(self, model, **hints):
# """
# Attempts to write aew models go to aew DB.
# """
# if model._meta.app_label == 'app01':
# return 'default'
# return None # def allow_relation(self, obj1, obj2, **hints):
# """
# Allow relations if a model in the aew app is involved.
# """
# if obj1._meta.app_label == 'app01' or obj2._meta.app_label == 'app01':
# return True
# return None # def allow_migrate(self, db, model):
# """
# Make sure the aew app only appears in the aew database.
# """
# if db == 'default':
# return model._meta.app_label == 'app01'
# elif model._meta.app_label == 'app01':
# return False
# return None
router.py
class tb05(models.Model): #该model使用default数据库
name=models.CharField(max_length=100,primary_key=True,unique=True)
ip=models.GenericIPAddressField()
rating = models.IntegerField() def __str__(self):
return self.name class Meta:
#app_label = 'app01' #由于该model连接default数据库,所以在此无需指定
ordering = ['name'] class tb2(models.Model):
name=models.CharField(max_length=100,primary_key=True,unique=True)
ip=models.GenericIPAddressField()
rating = models.IntegerField() def __str__(self):
return self.name class Meta:
app_label = 'app02'
ordering = ['name']
models.py(app01)
class mtable01(models.Model):
name=models.CharField(max_length=100,primary_key=True,unique=True)
ip=models.GenericIPAddressField()
rating = models.IntegerField() def __str__(self):
return self.name class Meta:
app_label = 'app02' #定义该model的app_label
ordering = ['name'] 使用migrate命令同步数据库: class tb06(models.Model):
name=models.CharField(max_length=100,primary_key=True,unique=True,db_column='mycname') #使用db_column自定义字段名称
ip=models.GenericIPAddressField()
rating = models.IntegerField() def __str__(self):
return self.name class Meta:
db_table = 'mytable' #自定义表名称为mytable
verbose_name = '自定义名称' #指定在admin管理界面中显示的名称
app_label = 'app02'
ordering = ['name']
models.py(app02)
migrate管理命令一次操作一个数据库。默认情况下,它在default 数据库上操作,但是通过提供一个 --database 参数,告诉migrate同步一个不同的数据库。
1)同步default节点数据库,只运行不带 --database参数的命令,不对其他数据库进行同步
python manage.py migrate
python manage.py makemigrations
python manage.py migrate
2)同步hvdb节点数据库:
python manage.py migrate --database=hvdb
python manage.py makemigrations
python manage.py migrate --database=hvdb
结果:
testdjango数据库(hvdb节点)下的app02_mtable01表对应app02下的mtable01模型
testdjango数据库(hvdb节点)下的app02_tb2表对应app01下的tb2模型
testly数据库(default节点)下的app01_tb05表对应app01下的tb05模型
实测
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',
'NAME':'review_scrapy_dj',
'USER': 'xxxx',
'PASSWORD': 'xxxx',
'HOST': '1.1.1.39',
'PORT': '',
'CHARSET':'utf8',
"COLLATION":'utf8_general_ci'
},
"slave":{
'ENGINE': 'django.db.backends.sqlite3',
'NAME': os.path.join(BASE_DIR, 'db2.sqlite3'),
}
} DATABASE_ROUTERS = ['utils.myrouter.Router',] # router
settings.py
# -*- coding:utf-8 -*- class Router:
def db_for_read(self, model, **hints):
return 'slave' def db_for_write(self, model, **hints):
return 'default'
utils/myrouter.py
from django.db import models # Create your models here. class UserInfo(models.Model):
name = models.CharField(max_length=64)
gender_choices = [
(0, "男"),
(1, "女"),
]
gender = models.IntegerField(choices=gender_choices,null=True,default=None) class Role(models.Model):
role = models.CharField(max_length=64)
user = models.ManyToManyField(to="UserInfo")
models.py
from django.shortcuts import render,HttpResponse,redirect
from django.views import View
from . import models
# Create your views here.
class Index(View):
def get(self,request):
user_objs_read = models.UserInfo.objects.all()
user_objs_default = models.UserInfo.objects.using("default").all()
gender_choices = models.UserInfo.gender_choices context = {
"user_objs_read":user_objs_read,
"gender_choices":gender_choices,
"user_objs_default":user_objs_default,
} return render(request,"index.html",context=context)
def post(self,request):
name = request.POST.get("name")
print(type(request.POST.get("gender")))
gender = int(request.POST.get("gender"))
models.UserInfo.objects.create(name=name,gender=gender)
return redirect("/test2db/")
views.py
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h1>index</h1>
<div>
<h3>user_objs_read</h3>
{% for user_obj in user_objs_read %}
<div>{{ user_obj.name }}——{{ user_obj.get_gender_display }}</div>
{% endfor %}
</div>
<hr>
<div>
<h3>user_objs_write</h3>
{% for foo in user_objs_default %}
<div>{{ foo.name }}——{{ foo.get_gender_display }}</div>
{% endfor %}
</div>
<hr>
<form action="" method="post">
{% csrf_token %}
<div>name<input type="text" name="name"></div>
<div>gender
<select name="gender" id="">
{% for gender_choice in gender_choices %}
<option value="{{ gender_choice.0 }}">{{ gender_choice.1 }}</option>
{% endfor %}
</select>
</div>
<input type="submit">
</form> </body>
</html>
index.html
(转)Django配置数据库读写分离的更多相关文章
- Django的数据库读写分离
Django的数据库读写分离 1.首先是配置数据库 在settings.py文件中增加多个数据库的配置: DATABASES = { 'default': { 'ENGINE': 'django.db ...
- 配置Django中数据库读写分离
django在进行数据库操作的时候,读取数据与写数据(曾.删.改)可以分别从不同的数据库进行操作 修改配置文件: DATABASES = { 'default': { 'ENGINE': 'djang ...
- Django----配置数据库读写分离
Django配置数据库读写分离 https://blog.csdn.net/Ayhan_huang/article/details/78784486 https://blog.csdn.net/ayh ...
- django数据库读写分离
django数据库读写分离 1. 配置数据库 settings.py文件中 用SQLite: DATABASES = { 'default': { 'ENGINE': 'django.db.backe ...
- linux中MySQL主从配置(Django实现主从读写分离)
一 linux中MySQL主从配置原理(主从分离,主从同步) mysql主从配置的流程大体如图: 1)master会将变动记录到二进制日志里面: 2)master有一个I/O线程将二进制日志发送到sl ...
- EF架构~通过EF6的DbCommand拦截器来实现数据库读写分离~终结~配置的优化和事务里读写的统一
回到目录 本讲是通过DbCommand拦截器来实现读写分离的最后一讲,对之前几篇文章做了一个优化,无论是程序可读性还是实用性上都有一个提升,在配置信息这块,去除了字符串方式的拼接,取而代之的是sect ...
- yii2的数据库读写分离配置
简介 数据库读写分离是在网站遇到性能瓶颈的时候最先考虑优化的步骤,那么yii2是如何做数据库读写分离的呢?本节教程来给大家普及一下yii2的数据库读写分离配置. 两个服务器的数据同步是读写分离的前提条 ...
- centos MySQL主从配置 ntsysv chkconfig setup命令 配置MySQL 主从 子shell MySQL备份 kill命令 pid文件 discuz!论坛数据库读写分离 双主搭建 mysql.history 第二十九节课
centos MySQL主从配置 ntsysv chkconfig setup命令 配置MySQL 主从 子shell MySQL备份 kill命令 pid文件 discuz!论坛数 ...
- 使用Adivisor配置增强处理,来实现数据库读写分离
一.先写一个demo来概述Adivisor的简单使用步骤 实现步骤: 1.通过MethodBeforeAdivice接口实现前置增强处理 public class ServiceBeforeAdvis ...
随机推荐
- TensorFlow入门:线性回归
随机.mini-batch.batch(见最后解释) 在每个 epoch 送入单个数据点.这被称为随机梯度下降(stochastic gradient descent).我们也可以在每个 epoch ...
- 定义一个复数(z=x+iy)类Complex,包含: 两个属性:实部x和虚部y 默认构造函数 Complex(),设置x=0,y=0 构造函数:Complex(int i,int j) 显示复数的方法:showComp()将其显示为如: 5+8i或5-8i 的形式。 求两个复数的和的方法:(参数是两个复数类对象,返回值是复数类对象)public Complex addComp(Compl
因标题框有限,题目未显示完整,以下再放一份: 定义一个复数(z=x+iy)类Complex,包含: 两个属性:实部x和虚部y 默认构造函数 Complex(),设置x=0,y=0 构造函数:Compl ...
- PAT乙级1005
1005 继续(3n+1)猜想 (25 分) 卡拉兹(Callatz)猜想已经在1001中给出了描述.在这个题目里,情况稍微有些复杂. 当我们验证卡拉兹猜想的时候,为了避免重复计算,可以记录下递推过程 ...
- NYOJ 18 The Triangle 填表法,普通dp
题目链接: http://acm.nyist.edu.cn/JudgeOnline/problem.php?pid=18 The Triangle 时间限制:1000 ms | 内存限制:6553 ...
- Oracle ora-12514监听程序当前无法识别连接描述中请求的错误
昨天刚安装好oracle数据库,还可以登录,到今天,登录时就发出了这样的错误 到网上找了半天,上面都是说监听器服务的问题,但是试过后依旧不行.最后重启了一次,就解决了异常 原来是oracle中一个服务 ...
- day 84 Vue学习四之过滤器、钩子函数、路由、全家桶等
本节目录 一 vue过滤器 二 生命周期的钩子函数 三 vue的全家桶 四 xxx 五 xxx 六 xxx 七 xxx 八 xxx 一 Vue的过滤器 1 moment.js 在这里我们先介绍一个 ...
- doc2vec使用笔记
#!/usr/bin/env Python # coding:utf-8 #improt依赖包 # import sys # reload(sys) # sys.setdefaultencoding( ...
- 洛谷 P1337 [JSOI2004]平衡点 / 吊打XXX
洛谷 P1337 [JSOI2004]平衡点 / 吊打XXX 点击进入FakeHu的模拟退火博客 神仙模拟退火...去看fakehu的博客吧...懒得写了... 因为精度问题要在求得的最优解附近(大约 ...
- Java的自动拆/装箱
作者:Alvin 关键字:语法糖 类 对象 参考 Java 中的语法糖 语法糖--这一篇全了解 浅谈 Integer 类 什么是Java中的自动拆装箱 深入剖析Java中的装箱和拆箱 前言 我们知道, ...
- Distributed1:链接服务器
链接服务器(Linked Server)允许访问针对OLE DB数据源的分布式异构查询, 通过使用sys.sp_addlinkedserver创建链接服务器后,可以对此服务器运行分布式查询. 如果链接 ...