首页 > 技术文章 > mysql事务、锁

zezhou 原文

事务: 

目的:

把所有小环节当成一个环节, 小环节一个出错 就整体失败,要么都成功,要么都不成功。

例如:A给B转钱,是两个小环节,A减钱、B加钱,中间任意环节出错,都表示不成功。

排他锁:

介绍:

行级锁,锁住之后,其他人就操作不了该行信息,会陷入阻塞状态直到前面的用户commit或rollback之后才可操作。

使用场景:

例如转钱,一个客户给另一个客户转钱,然后需要两行内容都先上锁保证数据安全,再修改内容,修改完提交,另一个人再操作改行内容。

使用方式:

select 字段 from 表名  where 索引字段=值 for update;   // 行级上锁写法,必须是建立了索引字段 (如主键)

需要注意的问题:

1. 有可能造成死锁,例如A给B转钱,B也再给A转钱,A、B同时锁了自己的行数据,之后A等B的锁释放,B等A的锁释放,就成了死锁状态,最后一个会自动报错,第一个人直接锁住他的行数据。

2. for update是加上锁了,只是同for update语句或删除、修改会陷入阻塞,不影响改行查询语句不加for update的。 

排他锁例子:

 

死锁例子:

Django的ORM写法:(排他锁)(一个锁的情况)

from django.db import transaction

# 某一个视图函数函数的用法
class Recharge(View): def post(self, req): data = json.loads(req.body) # 开启事务,当中有任何地方报错,则自动回滚到开启事务的地方 with transaction.atomic(): # 1. 查询商户数据,id为这个的加了个 行锁 business_obj = Business.objects.select_for_update().get(id=data["business_id"]) # 2. 创建交易记录 BusinessTransaction.objects.create(**{ "t_type": 0, "money": data["money"], "balance": business_obj.integral, "pay_method": data["pay_method"], "business_id": business_obj.id }) # 3. 更新积分 new_integral = business_obj.integral + (int(data["money"]) * recharge_ratio) Business.objects.filter(id=data["business_id"]).update(integral=new_integral) res = {"status": 0, "message": "充值成功!"} return HttpResponse(json.dumps(res))

# Business.objects.select_for_update().get(id=data["business_id"])   加锁的过程,当再有充值操作,到这一步骤,遇到相同的id会进入等待

注:该例子只是单个表一行的情况,如果涉及多行或多个表,需要加多个锁达到一致性

# 事务回滚

# 1. 手动回滚(无法报错时候用)

# 开启事务
with transaction.atomic():

    # 记录保存点
    save_id = transaction.savepoint()
    
    # 回滚到保存点
    transaction.savepoint_rollback(save_id)

 # 2. 主动抛出异常或报错,会自动恢复到with那里

共享锁:

推荐阅读