mysql事务、锁
事务:
目的:
把所有小环节当成一个环节, 小环节一个出错 就整体失败,要么都成功,要么都不成功。
例如: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那里
共享锁: