对网站的数据库作读写分离(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‘),
},
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
创建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)
- 1
- 2
- 3
- 4
- 5
- 6
- 7
创建完成后,执行数据库迁移操作:
python manage.py makemigrations # 在migrations文件夹下生成记录,迁移前检查
python manage.py migrate # 创建表
- 1
- 2
在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)
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
自动读写分离
通过配置数据库路由,来自动实现,这样就不需要每次读写都手动指定数据库了。数据库路由中提供了四个方法。这里这里主要用其中的两个: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‘
- 1
- 2
- 3
- 4
- 5
- 6
配置Router
settings.py
中指定DATABASE_ROUTERS
DATABASE_ROUTERS = [‘myrouter.Router‘,]
- 1
可以指定多个数据库路由,比如对于读操作,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‘
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
分库分表
在大型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‘
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
更多请参考官网
原文地址:https://www.cnblogs.com/mjc69213/p/9941046.html