当一个项目当中有大量的数据的时候,你所有的 IO 操作都在一个数据库中操作,会造成项目的性能的降低。如果你能对项目中的数据进行读写分离的话,那么将大大提高你项目的性能。而 Django 自带的机制也对此提供了支持。我们可以简单的操作一下。(当然数据的同步还是需要运维同志的协助)
Django 默认的是default
, 我们按照它的格式直接添加一个新的配置:
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'), } }
当然,如果你不想使用默认的 sqlite3,想使用 mysql 还需要自己进行一下配置
DATABASES = { 'default': { 'ENGINE': 'django.db.backends.mysql', 'HOST': '127.0.0.1', # 主服务器的运行ip 'PORT': 3306, # 主服务器的运行port 'USER': 'django', # 主服务器的用户名 'PASSWORD': 'django', # 主服务器的密码 'NAME': 'djangobase' # 数据表名 }, 'slave': { 'ENGINE': 'django.db.backends.mysql', 'HOST': '127.0.0.1', 'PORT': 8306, 'USER': 'django_slave', 'PASSWORD': 'django_slave', 'NAME': 'djangobase_slave' } }
在项目目录下的__init__
文件中添加以下代码,将数据连接方式改为 pymysql
import pymysql pymysql.install_as_MySQLdb()
将数据配置修改完之后就可以在 models.py 文件当中创建表,接下里就可以进行数据库迁移了
python manage.py makemigrations # 在migrations文件夹下生成记录 python manage.py migrate --database default # 默认可以不写参数 python manage.py migrate --database db2 # 在从库再迁移一次,就可以在上面建立相同的表
在遇到数据库相关操作的话,需要手动指定要使用的相应数据库,不需要进行多余的配置,但是,当你数据的读写操作过于频繁的时候,这个方法就会略显繁琐。
from django.shortcuts import render, HttpResponse from app001 import models # Create your views here. def write(request): models.User.objects.using('default').create(name='张三', pwd='123', phone=1234) return HttpResponse('写成功') def read(request): obj = models.User.objects.filter(id=1).using('db2').first() return HttpResponse('读成功')
通过配置数据库路由,来自动实现读写分离,这样就不需要每次读写都手动指定数据库。
在项目的 app 中创建 db_router.py 文件, 并在该文件中定义一个数据库路由类, 用来进行读写分离,这个类最多提供四个方法,分别是:db_for_read
、db_for_write
、allow_relation
、allow_migrate
,以下只写了三个。
class MasterSlaveDBRouter(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
DATABASE_ROUTERS = ["app001.db_router.MasterSlaveDBRouter"]
可以指定多个数据库路由,比如对于读操作,Django 将会循环所有路由中的db_for_read()
方法,直到其中一个有返回值,然后使用这个数据库进行当前操作。
# 一主多从 import random class Router: def db_for_read(self, model, **kwargs): return random.choices(['db1', 'db2', 'db3']) def db_for_write(self, model, **kwargs): return 'db'
# 分库分表 # app01 db1 app02 db2 class Router: # 读 def db_for_read(self, model, **kwargs): if model._meta.app_label == 'app01': return 'db1 ' elif model._meta.app_label == 'app02': return 'db2' # 写 def db_for_write(self, model, **kwargs): if model._meta.app_label == 'app01': return 'db1 ' elif model._meta.app_label == 'app02': return 'db2'