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

配置全局事务

复制代码
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

相关推荐
源代码•宸8 小时前
goframe框架签到系统项目(BITFIELD 命令详解、Redis Key 设计、goframe 框架教程、安装MySQL)
开发语言·数据库·经验分享·redis·后端·mysql·golang
思成不止于此10 小时前
【MySQL 零基础入门】事务精讲(二):ACID 特性与并发问题
数据库·笔记·学习·mysql
Boilermaker199210 小时前
[MySQL] 初识 MySQL 与 SQL 基础
数据库·mysql
Boilermaker199211 小时前
[MySQL] 服务器架构
数据库·mysql·架构
qualifying12 小时前
MySQL——表的操作
数据库·mysql
学Linux的语莫13 小时前
mysql主从同步(复制)搭建
数据库·mysql
MySQL实战13 小时前
MySQL 在哪些场景下不会写 binlog
mysql
苹果酱056713 小时前
解决linux mysql命令 bash: mysql: command not found 的方法
java·vue.js·spring boot·mysql·课程设计
问道飞鱼14 小时前
【数据库知识】MySQL 多表关联高效实现指南:场景化方案与底层原理
数据库·mysql·多表关联
dblens 数据库管理和开发工具14 小时前
MySQL :5.7与8.0版创建用户与授权、密码认证插件、角色、密码过期策略
数据库·mysql·dblens·mysql创建用户·mysql设置密码·mysql用户授权