前期準備
# 線上賣圖書-圖書表 圖書名字,圖書價格,庫存字段-訂單表: 訂單id,訂單名字# 表準備class Book(models.Model):name = models.CharField(max_length=32)price = models.IntegerField() #count = models.SmallIntegerField(verbose_name='庫存')class Order(models.Model):order_id = models.CharField(max_length=64)order_name = models.CharField(max_length=32)# 使用mysql
DATABASES = {'default': {'ENGINE': 'django.db.backends.mysql','NAME': 'lqz','HOST': '127.0.0.1','PORT': '3306','USER': 'lqz','PASSWORD': '123',}
}# 創建lqz數據庫
1.原生mysql悲觀鎖
begin; # 開啟事務select * from goods where id = 1 for update; # 行鎖# order表中加數據update goods set stock = stock - 1 where id = 1; # 更新commit; #提交事務
2.orm實現上述(悲觀鎖)?
#1 使用悲觀鎖實現下單
@transaction.atomic # 整個過程在一個事物中---》改兩個表:book表減庫存,訂單表生成記錄
def seckill(request):# 鎖住查詢到的book對象,直到事務結束sid = transaction.savepoint() # 保存點# 悲觀鎖: select_for_update()# 加鎖了--》行鎖還是表鎖? 分情況,都有可能#book = Book.objects.select_for_update().filter(pk=1).first() # 加悲觀鎖,行鎖,鎖住當前行if book.count > 0:print('庫存可以,下單')# 訂單表插入一條Order.objects.create(order_id=str(datetime.datetime.now()), order_name='測試訂單')# 庫存-1,扣減的時候,判斷庫存是不是上面查出來的庫存,如果不是,就回滾time.sleep(random.randint(1, 4)) # 模擬延遲book.count=book.count-1book.save()transaction.savepoint_commit(sid) # 提交,釋放行鎖return HttpResponse('秒殺成功')else:transaction.savepoint_rollback(sid) #回滾,釋放行鎖return HttpResponse('庫存不足,秒殺失敗')
3 樂觀鎖秒殺--》庫存還有,有的人就沒成功
# 2 樂觀鎖秒殺--普通版
@transaction.atomic
def seckill(request):# 鎖住查詢到的book對象,直到事務結束sid = transaction.savepoint()book = Book.objects.filter(pk=1).first() # 沒加鎖count = book.countprint('現在的庫存為:%s' % count)if book.count > 0:print('庫存可以,下單')Order.objects.create(order_id=str(datetime.datetime.now()), order_name='測試訂單-樂觀鎖')# 庫存-1,扣減的時候,判斷庫存是不是上面查出來的庫存,如果不是,就回滾# time.sleep(random.randint(1, 4)) # 模擬延遲res = Book.objects.filter(pk=1, count=count).update(count=count - 1)if res >= 1: # 表示修改成功transaction.savepoint_commit(sid)return HttpResponse('秒殺成功')else: # 修改不成功,回滾transaction.savepoint_rollback(sid)return HttpResponse('被別人改了,回滾,秒殺失敗')else:transaction.savepoint_rollback(sid)return HttpResponse('庫存不足,秒殺失敗')
?