事务、并发、锁机制的实现

配置全局事务

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.mysql',
        'NAME': 'mydb',
        'USER':'root',
        'PASSWORD':'pass',
        'HOST':'127.0.0.1',
        'PORT':3306,
        'ATOMIC_REQUESTS': True,  # 全局开启事务,绑定的是http请求响应整个过程
        # (non_atomic_requests可局部实现不让事务控制)
    }
}

配置全局事务中局部不受事务控制

# 1.不受全局事务控制
# 如有多个数据库,让使用db的视图不受事务控制
@transaction.non_atomic_requests(using='db')
def my_other_view(request):
    pass

回滚点配置保存及提交

sid = transaction.savepoint()  # 回滚点
with transaction.atomic():
    try:
        pass
    except Exception as e:
        # 如发生异常,回滚到指定地方。
        transaction.savepoint_rollback(sid)
    # 如果没有异常,显式地提交一次事务
    transaction.savepoint_commit(sid)

悲观锁的实现

# django实现悲观锁
@transaction.atomic
def post(self, request):
    # select_for_update表示锁,只有获取到锁才会执行查询,否则阻塞等待。
    xxx.objects.select_for_update().get(id=1)
    # 等事务提交后,会自动释放锁。


# 同时使用select_for_update与select_related
# 只会锁定entry(self)和category,不会锁定作者author
xxx.objects.select_related('author', 'category').select_for_update(of=('self', 'category'))
# 注意:MySQL版本要在8.0.1 以上才支持 nowait,skip_locked和of选项。

乐观锁的实现

# 乐观锁实现
@transaction.atomic
def post(self, request):
    goods_id = request.GET.get('id')
    count = int(request.GET.get('count'))
    while True:
        # 查询商品对象 -- 最基本查询
        goods = xxx.objects.filter(id=goods_id).first()
        origin_stock = goods.stock  # 获取原始库存,会检查是否有变化,乐观锁的特点
        sleep(5)
        # 减少商品的库存数量,保存到数据库
        xxx.objects.filter(id=goods_id, stock=origin_stock).update(stock=origin_stock - count)

mysql 的主从搭建的原因:

1.实现读写分离,多个msyql可实现提高并发量

2.主库写数据,从库读数据

docker ``pull mysql:5.7

创建文件夹,配置mysql1主,mysql2从数据库

mkdir /root/mysql1

mkdir /root/mysql1/conf.d

mkdir /root/mysql2/data/

touch /root/mysql2/my.cnf

mkdir /root/mysql2

mkdir /root/mysql2/conf.d

mkdir /root/mysql2/data/

touch /root/mysql2/my.cnf

配置主从数据库

主:/root/mysql1/my.cnf

主
[mysqld]
user=mysql
character-set-server=utf8
default_authentication_plugin=mysql_native_password
secure_file_priv=/var/lib/mysql
expire_logs_days=7
sql_mode=STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION
max_connections=1000
server-id=100                   # id
log-bin=mysql-bin               # bin
[client]
default-character-set=utf8
 
[mysql]
default-character-set=utf8

从:/root/mysql2/my.cnf

[mysqld]
user=mysql
character-set-server=utf8
default_authentication_plugin=mysql_native_password
secure_file_priv=/var/lib/mysql
expire_logs_days=7
sql_mode=STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION
max_connections=1000
server-id=101                  # id
log-bin=mysql-slave-bin         # bin
relay_log=edu-mysql-relay-bin 
 
[client]
default-character-set=utf8
 
[mysql]
default-character-set=utf8

启动mysql,设置端口和目录的映射

主库容器设置

docker run -di -v /root/mysql1/data/:/var/lib/mysql -v /root/mysql1/conf.d:/etc/mysql/conf.d -v /root/mysql1/my.cnf:/etc/mysql/my.cnf -p 33307:3306 --name mysql-master -e MYSQL_ROOT_PASSWORD=123456 mysql:5.7

从库容器设置

docker run -di -v /root/mysql2/data/:/var/lib/mysql -v /root/mysql2/conf.d:/etc/mysql/conf.d -v /root/mysql2/my.cnf:/etc/mysql/my.cnf -p 33306:3306 --name mysql-slave -e MYSQL_ROOT_PASSWORD=123456 mysql:5.7
docker ps 可查看运行的mysql容器

连接主库

mysql -uroot -P33307 -h 10.0.0.200 -p123456

再主库创建用户并授予所以权限

创建用户test

create user 'test'@'%' identified by '123';

授权

grant all privileges on *.* to 'test'@'%' ;

刷新权限

flush privileges;

查看主状态

show master status;

连接从数据库

change master to master_host='10.0.0.200',master_port=33307,master_user='test',master_password='123',master_log_file='mysql-bin.000003',master_log_pos=0;

命令详细解释

  • change master to
  • master_host='MySQL主服务器IP地址',
  • master_user='之前在MySQL主服务器上面创建的用户名',
  • master_password='之前创建的密码',
  • master_log_file='MySQL主服务器状态中的二进制文件名',
  • master_log_pos='MySQL主服务器状态中的position值';

这时在主数据库中写入数据,可在从数据库中查看;

注若测试在从数据库中写入数据会导致主从冲突,造成主从断开

可以通过下发如下命令解决

stop slave; # 先停止主从库

set GLOBAL SQL_SLAVE_SKIP_COUNTER=2; # 这里是跳过binlog的命令条数

start slave; # 启动主从就ok了

django的多数据的读写分离

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.sqlite3',
        'NAME': BASE_DIR / 'db.sqlite3',
    },
    'db1': {
        'ENGINE': 'django.db.backends.sqlite3',
        'NAME': BASE_DIR / 'db1.sqlite3',
    }
}

migrate --database db1 app01 # 迁移指定数据库

手动测试读写分离:

Book.objects.using('db1').create(name='xxx')

自动测试读写分离:

class DBRouter(object):

def db_for_read(self, model, **hints):

多个从库 ['db1','db2','db3']

model是哪个模型表

return 'db1'

def db_for_write(self, model, **hints):

return 'default'
DATABASE_ROUTERS = ['utils.db_router.DBRouter', ] # 配置setting

借鉴博客:https://www.cnblogs.com/clever-cat/p/17356820.html

相关推荐
苹果醋32 小时前
大模型实战--FastChat一行代码实现部署和各个组件详解
java·运维·spring boot·mysql·nginx
计算机学姐5 小时前
基于SpringBoot+Vue的高校运动会管理系统
java·vue.js·spring boot·后端·mysql·intellij-idea·mybatis
-XWB-5 小时前
【MySQL】数据目录迁移
数据库·mysql
掘根7 小时前
【MySQL】Ubuntu环境下MySQL的安装与卸载
数据库·mysql·centos
知识分享小能手7 小时前
mysql学习教程,从入门到精通,SQL 修改表(ALTER TABLE 语句)(29)
大数据·开发语言·数据库·sql·学习·mysql·数据分析
暮毅8 小时前
Django对接支付宝沙箱环境(2024年9月新测有效)
数据库·django
fat house cat_8 小时前
mysql-索引笔记
数据库·mysql
He guolin8 小时前
【MySQL】数据库基础知识
数据库·mysql
yz_518 Nemo8 小时前
django的路由分发
后端·python·django
向上的车轮9 小时前
Django学习笔记八:发布RESTful API
笔记·学习·django