有个买东西的网站,你下单买了某个货品,那么数据库中的订单表会插入一条你下单的记录,同时货物表需要把你所购买货品的数量进行更新,候新增订单和更新货品数量必须是一致的,不应该出现有人下了单但是货品数量不变,也不应该货品数量减少了而订单却没有新增这种情况发生
那么插入订单信息和更新货品数量就是一个完整的事务,要么都执行成功,如果两个 *** 作中有任意一个 *** 作失败,则整个流程就应该是失败的,已经执行的 *** 作就应当回滚
在数据库中使用事务,可以保证多个数据库 *** 作的一致性
这就是一个简单的事务的使用场景
本文死锁场景皆为工作中遇到(或同事遇到)并解决的死锁场景,写这篇文章的目的是整理和分享,欢迎指正和补充,本文死锁场景包括:
注 :以下场景隔离级别均为默认的Repeatable Read;
前提 :表 t_user 的 uid 字段创建了唯一索引,并拥有可更新字段age。
场景复现 :
相应业务案例和解决方案 :
该场景常见于事务中存在for循环更新某条记录的情况,死锁日志显示 lock_mode X locks rec but not gap waiting (即行锁而非间隙锁),解决方案:
表结构 :
场景复现 :
首先查询表中目前存在的记录:
执行两个事务的 *** 作:
死锁原因分析 :
解决方案 :
t_user结构改造为:
场景复现 *** 作(几率不高) :
假设存在以下数据 :
死锁分析 :
事务1 :
① 锁住zone_id=1对应的间隙锁: zoneId in (1,2)
② 锁住索引zone_id=1对应的主键索引行锁id = [1,2]
③ 锁住uid=1对应的间隙锁: uid in (1, 2)
④ 锁住uid=1对应的主键索引行锁: id = [1, 3]
事务2 :
① 锁住zone_id=2对应的间隙锁: zoneId in (1,2)
② 锁住索引zone_id=2对应的主键索引行锁id = [3,4]
③ 锁住uid=2对应的间隙锁: uid in (1, 2)
④ 锁住uid=2对应的主键索引行锁: id = [2, 4]
解决方案 :创建联合索引,使执行计划只会用到一个索引。
测试表结构 :
场景复现 *** 作 :
解决办法:尽量避免这种插入又回滚的场景。
避免死锁的原则:
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)