django mysql读写分离_(转)Django配置数据库读写分离

目录

简述

对网站的数据库作读写分离(Read/Write Splitting)可以提高性能,在Django中对此提供了支持,下面我们来简单看一下。注意,还需要运维人员作数据库的读写分离和数据同步。

配置数据库

我们知道在Django项目的settings中,可以配置数据库,除了默认的数据库,我在下面又加了一个db2。因为是演示,我这里用的是默认的SQLite,如果希望用MySQL,看这里 。

创建models并执行数据库迁移

这里我简单创建一张产品表

创建完成后,执行数据库迁移操作:

在migrations文件夹下生成记录,并在迁移前检查是否有问题,默认值检查defualt数据库,但是可以在后面的数据库路由类(Router)中通过allow_migrate()方法来指定是否检查其它的数据库。

其实第二步迁移默认有参数python manage.py migrate --database default ,在默认数据库上创建表。因此完成以上迁移后,执行python manage.py --database db2,再迁移一次,就可以在db2上创建相同的表。这样在项目根目录下,就有了两个表结构一样的数据库,分别是db.sqlite3和db2.sqlite3。

读写分离

手动读写分离

在使用数据库时,通过.using(db_name)来手动指定要使用的数据库

自动读写分离

通过配置数据库路由,来自动实现,这样就不需要每次读写都手动指定数据库了。数据库路由中提供了四个方法。这里这里主要用其中的两个:def db_for_read()决定读操作的数据库,def db_for_write()决定写操作的数据库。

定义Router类

新建myrouter.py脚本,定义Router类:

配置Router

settings.py中指定DATABASE_ROUTERS

可以指定多个数据库路由,比如对于读操作,Django将会循环所有路由中的db_for_read()方法,直到其中一个有返回值,然后使用这个数据库进行当前操作。

一主多从方案

网站的读的性能通常更重要,因此,可以多配置几个数据库,并在读取时,随机选取,比如:

分库分表

在大型web项目中,常常会创建多个app来处理不同的业务,如果希望实现app之间的数据库分离,比如app01走数据库db1,app02走数据库

例子

别人的例子

8f900a89c6347c561fdf2122f13be562.png

961ddebeb323a10fe0623af514929fc1.png

DATABASES ={'default': {'ENGINE': 'django.db.backends.mysql','NAME': 'testly','USER': 'root','PASSWORD': '123456789','HOST':'192.168.1.1','PORT':'3306',

},'hvdb':{ #配置第二个数据库节点名称

'ENGINE': 'django.db.backends.mysql','NAME': 'testdjango', #第二个数据库的名称

'USER': 'root','PASSWORD': '123456789','HOST':'192.168.1.1','PORT':'3306',

}

}

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

8f900a89c6347c561fdf2122f13be562.png

961ddebeb323a10fe0623af514929fc1.png

#-*- 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

returnNonedef db_for_write(self, model, **hints):"""Attempts to write app02 models go to hvdb DB."""

if model._meta.app_label == 'app02':return 'hvdb'

returnNonedef 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':returnTruereturnNonedefallow_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':returnFalsedef 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

returnTruereturnNone#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

8f900a89c6347c561fdf2122f13be562.png

961ddebeb323a10fe0623af514929fc1.png

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):returnself.nameclassMeta:#app_label = 'app01' #由于该model连接default数据库,所以在此无需指定

ordering = ['name']classtb2(models.Model):

name=models.CharField(max_length=100,primary_key=True,unique=True)

ip=models.GenericIPAddressField()

rating=models.IntegerField()def __str__(self):returnself.nameclassMeta:

app_label= 'app02'ordering= ['name']

models.py(app01)

8f900a89c6347c561fdf2122f13be562.png

961ddebeb323a10fe0623af514929fc1.png

classmtable01(models.Model):

name=models.CharField(max_length=100,primary_key=True,unique=True)

ip=models.GenericIPAddressField()

rating=models.IntegerField()def __str__(self):returnself.nameclassMeta:

app_label= 'app02' #定义该model的app_label

ordering = ['name'] 使用migrate命令同步数据库:classtb06(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):returnself.nameclassMeta:

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模型

2e017b31f8ee7a9e7b16b10632d8a200.png

实测

8f900a89c6347c561fdf2122f13be562.png

961ddebeb323a10fe0623af514929fc1.png

DATABASES ={'default': {'ENGINE': 'django.db.backends.mysql','NAME':'review_scrapy_dj','USER': 'xxxx','PASSWORD': 'xxxx','HOST': '1.1.1.39','PORT': '3306','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

8f900a89c6347c561fdf2122f13be562.png

961ddebeb323a10fe0623af514929fc1.png

#-*- coding:utf-8 -*-

classRouter:def db_for_read(self, model, **hints):return 'slave'

def db_for_write(self, model, **hints):return 'default'

utils/myrouter.py

8f900a89c6347c561fdf2122f13be562.png

961ddebeb323a10fe0623af514929fc1.png

from django.db importmodels#Create your models here.

classUserInfo(models.Model):

name= models.CharField(max_length=64)

gender_choices=[

(0,"男"),

(1, "女"),

]

gender= models.IntegerField(choices=gender_choices,null=True,default=None)classRole(models.Model):

role= models.CharField(max_length=64)

user= models.ManyToManyField(to="UserInfo")

models.py

8f900a89c6347c561fdf2122f13be562.png

961ddebeb323a10fe0623af514929fc1.png

from django.shortcuts importrender,HttpResponse,redirectfrom django.views importViewfrom . importmodels#Create your views here.

classIndex(View):defget(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)defpost(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

8f900a89c6347c561fdf2122f13be562.png

961ddebeb323a10fe0623af514929fc1.png

Title

index

user_objs_read

{% for user_obj in user_objs_read %}
{{ user_obj.name }}——{{ user_obj.get_gender_display }}
{% endfor %}

user_objs_write

{% for foo in user_objs_default %}
{{ foo.name }}——{{ foo.get_gender_display }}
{% endfor %}

{% csrf_token %}

name
gender{% for gender_choice in gender_choices %}{{ gender_choice.1 }}{% endfor %}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值