转:https://blog.csdn.net/Ayhan_huang/article/details/78784486

转:http://www.cnblogs.com/dreamer-fish/p/5469141.html

目录

配置数据库

创建models并执行数据库迁移

读写分离

  手动读写分离

  自动读写分离

  配置Router

  一主多从方案

  分库分表

实测

简述

对网站的数据库作读写分离(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配置数据库读写分离的更多相关文章

  1. Django的数据库读写分离

    Django的数据库读写分离 1.首先是配置数据库 在settings.py文件中增加多个数据库的配置: DATABASES = { 'default': { 'ENGINE': 'django.db ...

  2. 配置Django中数据库读写分离

    django在进行数据库操作的时候,读取数据与写数据(曾.删.改)可以分别从不同的数据库进行操作 修改配置文件: DATABASES = { 'default': { 'ENGINE': 'djang ...

  3. Django----配置数据库读写分离

    Django配置数据库读写分离 https://blog.csdn.net/Ayhan_huang/article/details/78784486 https://blog.csdn.net/ayh ...

  4. django数据库读写分离

    django数据库读写分离 1. 配置数据库 settings.py文件中 用SQLite: DATABASES = { 'default': { 'ENGINE': 'django.db.backe ...

  5. linux中MySQL主从配置(Django实现主从读写分离)

    一 linux中MySQL主从配置原理(主从分离,主从同步) mysql主从配置的流程大体如图: 1)master会将变动记录到二进制日志里面: 2)master有一个I/O线程将二进制日志发送到sl ...

  6. EF架构~通过EF6的DbCommand拦截器来实现数据库读写分离~终结~配置的优化和事务里读写的统一

    回到目录 本讲是通过DbCommand拦截器来实现读写分离的最后一讲,对之前几篇文章做了一个优化,无论是程序可读性还是实用性上都有一个提升,在配置信息这块,去除了字符串方式的拼接,取而代之的是sect ...

  7. yii2的数据库读写分离配置

    简介 数据库读写分离是在网站遇到性能瓶颈的时候最先考虑优化的步骤,那么yii2是如何做数据库读写分离的呢?本节教程来给大家普及一下yii2的数据库读写分离配置. 两个服务器的数据同步是读写分离的前提条 ...

  8. centos MySQL主从配置 ntsysv chkconfig setup命令 配置MySQL 主从 子shell MySQL备份 kill命令 pid文件 discuz!论坛数据库读写分离 双主搭建 mysql.history 第二十九节课

    centos  MySQL主从配置 ntsysv   chkconfig  setup命令  配置MySQL 主从 子shell  MySQL备份  kill命令  pid文件  discuz!论坛数 ...

  9. 使用Adivisor配置增强处理,来实现数据库读写分离

    一.先写一个demo来概述Adivisor的简单使用步骤 实现步骤: 1.通过MethodBeforeAdivice接口实现前置增强处理 public class ServiceBeforeAdvis ...

随机推荐

  1. js之点击值发生变化

    点击值发生变化,应用场景,比如像阿里云那样我通常密码是以******的形式存在,我必须要点击查看,它才会以明文显示. 在实际开发中,比如以智能门锁为例,安装门锁时,有个叫密码输入框的表单,这个是选填项 ...

  2. ZOJ3202-Second-price Auction(根据输入输出判断是队列还是栈)

    A Stack or A Queue? Time Limit:1000MS     Memory Limit:32768KB     64bit IO Format:%lld & %llu S ...

  3. mapreduce二次排序详解

    什么是二次排序 待排序的数据具有多个字段,首先对第一个字段排序,再对第一字段相同的行按照第二字段排序,第二次排序不破坏第一次排序的结果,这个过程就称为二次排序. 如何在mapreduce中实现二次排序 ...

  4. linux中服务环境的搭建

    一.Samba服务 samba服务的安装及配置: sudo apt-get install samba 二.配置: 1.创建一个需要共享的目录,并修改权限: lpf@ubuntu:~$ mkdir l ...

  5. 【commons】IO工具类——commons-io之IOUtils

    本文转载自xingoo: https://www.cnblogs.com/xing901022/p/5978989.html 一.常用静态变量 public static final char DIR ...

  6. Hibernate第一天——入门和基本操作

    第一个接触的框架就是这个Hibernate框架了,Hibernate本意是 冬眠 ,这里有必要引用CSDN上某位网友某个帖子的评论先引出框架的概念: 框架:一个软件半成品,帮你做了一些基础工作,你就可 ...

  7. 2017-2018-1 20155310 《信息安全系统设计基础》 实现mypwd

    2017-2018-1 20155310 <信息安全系统设计基础> 实现mypwd 作业要求: 1.学习pwd命令 2.研究pwd实现需要的系统调用(man -k; grep),写出伪代码 ...

  8. 可以运行的Oracle Advanced Queue的例子

    通过查阅网上文章,发现很多Advanced Queue的例子无法跑起来. 参考了英文网站,可以正常运行成功. http://www.orafaq.com/wiki/Advanced_Queueing ...

  9. python基础学习1-三元表达式和lambda表达式

    #!/usr/bin/env python # -*- coding:utf-8 -*- 三元运算 if else 的简写 name ="alex" if 1==1 else &q ...

  10. 18-[模块]-random&os&sys

    1.random模块 程序中有很多地方需要用到随机字符,比如登录网站的随机验证码,通过random模块可以很容易生成随机字符串 # randrange #返回1-3之间的一个随机数,不包含3 # ra ...