python乐观锁和悲观锁

使用场景:

你银行卡现在100块,

A地花了10块,然后A地停电,会有延迟扣款

然后你的公司给你同时发了200工资,

如果公司先査你的钱100,同时A地查也是查到100

你公司先update了,你现在300,

然后A地扣除,你现在就是90块了.

这个地方乐观锁和悲观锁都可以选择作为使用.

乐观锁就是A地要更新的时候先回去查一下有没有被B地改了.

悲观锁就是A地读取数据的时候,直接把银行卡里的数据锁死,禁止除了自己以外的人写入.

那么,有没有可能一句sql中,select后,update之前,被第三方人写入截杀呢?

update salary_table set salary = salary + 1 where vesion = ***
cumt-pku-chiyu

这是不可能发生的,因为一句sql是保证完全事务的,复杂sql是自动开启事务的,

事物具有原子性,如果不理解什么是事物,可以参考[3]
(上述案例来自微信网友r_R403)

 

一些实践中的锁的判断方法(来自微信网友r_R403):

like %在前的是不走索引
主键也是索引

primary key和index都是走索引,导致行锁
其余都是表锁
不是全表扫描的都是行锁

举例(来自微信网友r_R403):

select  math  from zje where math>60 for update
表锁,悲观锁

select  math  from zje where id>60 for update
行锁,悲观锁

悲观锁就是sql里面带有for update

 

如果是在django中,那么悲观锁的实现方式如下[1]:

obj = 模型类名.objects.select_for_update().get(id=1)

乐观锁实现案例[1]:


from django.shortcuts import render
from django.http import JsonResponse
from django.views.generic import View
from django.db import transaction
from 应用名.models import GoodsSKU
 
 
# 类视图 (并发,乐观锁)
class MyView(View):
    
    @transaction.atomic
    def post(self, request):
        '''订单创建'''
        count = 3   # 订购3件商品
        
        # 设置事务保存点
        s1 = transaction.savepoint()
        
        # 乐观锁,最多尝试5次
        for i in range(5):
            # 查询商品的信息(库存)
            try:
                sku = GoodsSKU.objects.get(id=1)
            except:
                # 商品不存在
                transaction.savepoint_rollback(s1)
                return JsonResponse({'res': 1, 'errmsg': '商品不存在'})
 
            # 判断商品的库存
            if count > sku.stock:
                transaction.savepoint_rollback(s1)
                return JsonResponse({'res': 2, 'errmsg': '商品库存不足'})
 
            # 更新商品的库存和销量
            orgin_stock = sku.stock   # 原库存 (数据库隔离级别必须是Read Committed;如果是Repeatable Read,那么多次尝试读取的原库存都是一样的,读不到其他线程提交更新后的数据。)
            new_stock = orgin_stock - count   # 更新后的库存
            new_sales = sku.sales + count   # 更新后的销量
 
            # update 商品表 set stock=new_stock, sales=new_sales where id=1 and stock = orgin_stock
            # 通过where子句中的条件判断库存是否进行了修改。(并发,乐观锁)
            # 返回受影响的行数
            res = GoodsSKU.objects.filter(id=1, stock=orgin_stock).update(stock=new_stock, sales=new_sales)
            if res == 0:  # 如果修改失败
                if i == 4:
                    # 如果尝试5次都失败
                    transaction.savepoint_rollback(s1)
                    return JsonResponse({'res': 3, 'errmsg': '下单失败'})
                continue  # 再次尝试
 
            # 否则更新成功
            # 跳出尝试循环
            break
 
 
        # 提交事务
        transaction.savepoint_commit(s1)
 
        # 返回应答
        return JsonResponse({'res': 4, 'message': '创建成功'}

适用场景[2]:

适用场景
悲观锁 写入频繁
乐观锁 读取频繁

注意,上述这个表格在实际应用中没有标准细则,哪个能让系统吞吐大就用哪个

Reference:

[1]Python Django,并发,悲观锁,select_for_update。乐观锁

[2]乐观锁和悲观锁的原理及应用场景

[3]mysql的事务操作

你可能感兴趣的:(MySQL数据库)