当前位置: 首页 > news >正文

5050众筹网站开发福州餐饮网站建设

5050众筹网站开发,福州餐饮网站建设,学院网站的系统建设方式,男生学平面设计好就业吗作者#xff1a;小林coding提纲如下#xff1a;正文有个业务主要逻辑就是新增订单、修改订单、查询订单等操作。然后因为订单是不能重复的#xff0c;所以当时在新增订单的时候做了幂等性校验#xff0c;做法就是在新增订单记录之前#xff0c;先通过 select ... for upda… 作者小林coding提纲如下正文有个业务主要逻辑就是新增订单、修改订单、查询订单等操作。然后因为订单是不能重复的所以当时在新增订单的时候做了幂等性校验做法就是在新增订单记录之前先通过 select ... for update 语句查询订单是否存在如果不存在才插入订单记录。而正是因为这样的操作当业务量很大的时候就可能会出现死锁。接下来跟大家聊下为什么会发生死锁以及怎么避免死锁。死锁的发生 本次案例使用存储引擎 Innodb隔离级别为可重复读RR。接下来我用实战的方式来带大家看看死锁是怎么发生的。我建了一张订单表其中 id 字段为主键索引order_no 字段普通索引也就是非唯一索引CREATE TABLE t_order (id int NOT NULL AUTO_INCREMENT,order_no int DEFAULT NULL,create_date datetime DEFAULT NULL,PRIMARY KEY (id),KEY index_order (order_no) USING BTREE ) ENGINEInnoDB ;然后先 t_order 表里现在已经有了 6 条记录图片假设这时有两事务一个事务要插入订单 1007 另外一个事务要插入订单 1008因为需要对订单做幂等性校验所以两个事务先要查询该订单是否存在不存在才插入记录过程如下图片可以看到两个事务都陷入了等待状态前提没有打开死锁检测也就是发生了死锁因为都在相互等待对方释放锁。这里在查询记录是否存在的时候使用了 select ... for update 语句目的为了防止事务执行的过程中有其他事务插入了记录而出现幻读的问题。如果没有使用 select ... for update 语句而使用了单纯的 select 语句如果是两个订单号一样的请求同时进来就会出现两个重复的订单有可能出现幻读如下图为什么会产生死锁 可重复读隔离级别下是存在幻读的问题。Innodb 引擎为了解决「可重复读」隔离级别下的幻读问题就引出了 next-key 锁它是记录锁和间隙锁的组合。Record Loc记录锁锁的是记录本身Gap Lock间隙锁锁的就是两个值之间的空隙以防止其他事务在这个空隙间插入新的数据从而避免幻读现象。普通的 select 语句是不会对记录加锁的因为它是通过 MVCC 的机制实现的快照读如果要在查询时对记录加行锁可以使用下面这两个方式begin; //对读取的记录加共享锁 select ... lock in share mode; commit; //锁释放begin; //对读取的记录加排他锁 select ... for update; commit; //锁释放行锁的释放时机是在事务提交commit后锁就会被释放并不是一条语句执行完就释放行锁。比如下面事务 A 查询语句会锁住(2, ∞]范围的记录然后期间如果有其他事务在这个锁住的范围插入数据就会被阻塞。图片next-key 锁的加锁规则其实挺复杂的在一些场景下会退化成记录锁或间隙锁我之前也写一篇加锁规则详细可以看这篇「我做了一天的实验」需要注意的是如果 update 语句的 where 条件没有用到索引列那么就会全表扫描在一行行扫描的过程中不仅给行加上了行锁还给行两边的空隙也加上了间隙锁相当于锁住整个表然后直到事务结束才会释放锁。所以在线上千万不要执行没有带索引条件的 update 语句不然会造成业务停滞我有个读者就因为干了这个事情然后被老板教育了一波详细可以看这篇「完蛋公司被一条 update 语句干趴了」回到前面死锁的例子在执行下面这条语句的时候select id from t_order where order_no  1008 for update;因为 order_no 不是唯一索引所以行锁的类型是间隙锁于是间隙锁的范围是1006, ∞。那么当事务 B 往间隙锁里插入 id 1008 的记录就会被锁住。因为当我们执行以下插入语句时会在插入间隙上再次获取插入意向锁。Insert into t_order (order_no, create_date) values (1008, now());插入意向锁与间隙锁是冲突的所以当其它事务持有该间隙的间隙锁时需要等待其它事务释放间隙锁之后才能获取到插入意向锁。而间隙锁与间隙锁之间是兼容的所以所以两个事务中 select ... for update 语句并不会相互影响。案例中的事务 A 和事务 B 在执行完后 select ... for update 语句后都持有范围为(1006,∞的间隙锁而接下来的插入操作为了获取到插入意向锁都在等待对方事务的间隙锁释放于是就造成了循环等待导致死锁。为什么间隙锁与间隙锁之间是兼容的在MySQL官网上还有一段非常关键的描述Gap locks in InnoDB are “purely inhibitive”, which means that their only purpose is to prevent other transactions from Inserting to the gap. Gap locks can co-exist. A gap lock taken by one transaction does not prevent another transaction from taking a gap lock on the same gap. There is no difference between shared and exclusive gap locks. They do not conflict with each other, and they perform the same function.这段话表明间隙锁在本质上是不区分共享间隙锁或互斥间隙锁的而且间隙锁是不互斥的即两个事务可以同时持有包含共同间隙的间隙锁。这里的共同间隙包括两种场景其一是两个间隙锁的间隙区间完全一样其二是一个间隙锁包含的间隙区间是另一个间隙锁包含间隙区间的子集。间隙锁本质上是用于阻止其他事务在该间隙内插入新记录而自身事务是允许在该间隙内插入数据的。也就是说间隙锁的应用场景包括并发读取、并发更新、并发删除和并发插入。插入意向锁是什么注意插入意向锁名字虽然有意向锁但是它并不是意向锁它是一种特殊的间隙锁。在MySQL的官方文档中有以下重要描述An Insert intention lock is a type of gap lock set by Insert operations prior to row Insertion. This lock signals the intent to Insert in such a way that multiple transactions Inserting into the same index gap need not wait for each other if they are not Inserting at the same position within the gap. Suppose that there are index records with values of 4 and 7. Separate transactions that attempt to Insert values of 5 and 6, respectively, each lock the gap between 4 and 7 with Insert intention locks prior to obtaining the exclusive lock on the Inserted row, but do not block each other because the rows are nonconflicting.这段话表明尽管插入意向锁是一种特殊的间隙锁但不同于间隙锁的是该锁只用于并发插入操作。如果说间隙锁锁住的是一个区间那么「插入意向锁」锁住的就是一个点。因而从这个角度来说插入意向锁确实是一种特殊的间隙锁。插入意向锁与间隙锁的另一个非常重要的差别是尽管「插入意向锁」也属于间隙锁但两个事务却不能在同一时间内一个拥有间隙锁另一个拥有该间隙区间内的插入意向锁当然插入意向锁如果不在间隙锁区间内则是可以的。另外我补充一点插入意向锁的生成时机每插入一条新记录都需要看一下待插入记录的下一条记录上是否已经被加了间隙锁如果已加间隙锁那 Insert 语句应该被阻塞并生成一个插入意向锁 。Insert 语句是怎么加行级锁的 Insert 语句在正常执行时是不会生成锁结构的它是靠聚簇索引记录自带的 trx_id 隐藏列来作为隐式锁来保护记录的。什么是隐式锁当事务需要加锁的时如果这个锁不可能发生冲突InnoDB会跳过加锁环节这种机制称为隐式锁。隐式锁是 InnoDB 实现的一种延迟加锁机制其特点是只有在可能发生冲突时才加锁从而减少了锁的数量提高了系统整体性能。隐式锁就是在 Insert 过程中不加锁只有在特殊情况下才会将隐式锁转换为显示锁这里我们列举两个场景。如果记录之间加有间隙锁为了避免幻读此时是不能插入记录的如果 Insert 的记录和已有记录存在唯一键冲突此时也不能插入记录1、记录之间加有间隙锁每插入一条新记录都需要看一下待插入记录的下一条记录上是否已经被加了间隙锁如果已加间隙锁那 Insert 语句应该被阻塞并生成一个插入意向锁。举个例子现在 t_order 表中只有这些数据order_no 是二级索引。现在事务 A 执行了下面这条语句。# 事务 A mysql begin; Query OK, 0 rows affected (0.01 sec)mysql select * from t_order where order_no  1006 for update; Empty set (0.01 sec)接着我们执行 select * from performance_schema.data_locks\G; 语句  确定事务 A 加了什么类型的锁这里只关注在记录上加锁的类型。可以看到加的是 X 型得锁但是具体是记录锁、间隙锁、next-key 锁呢注意这里 LOCK_TYPE 中的 RECORD 表示行级锁而不是记录锁的意思。首先通过 LOCK_MODE 可以确认是「next-key 锁或者间隙锁」还是「记录锁」如果 LOCK_MODE 为 X说明是 next-key 锁或者间隙锁如果 LOCK_MODE 为 X, REC_NOT_GAP说明是记录锁。对于是 next-key 锁还是间隙锁就要看  LOCK_DATA 信息。如果 LOCK_DATA 信息为 supremum说明是间隙锁如果 LOCK_DATA 信息为具体的记录值说明是 next-key因此本次的例子加的是间隙锁间隙锁的范围是1005, ∞。然后有个事务 B 在这个间隙锁中插入了一个记录那么此时该事务 B 就会被阻塞# 事务 B 插入一条记录 mysql begin; Query OK, 0 rows affected (0.01 sec)mysql insert into t_order(order_no, create_date) values(1010,now()); ### 阻塞状态。。。。接着我们执行 select * from performance_schema.data_locks\G; 语句  确定事务 B 加了什么类型的锁这里只关注在记录上加锁的类型。可以看到事务 B 的状态为等待状态因为向事务 A 生成的间隙锁 1005, ∞ 中插入了一条记录所以事务 B 的插入操作生成了一个插入意向锁LOCK_MODE: X,INSERT_INTENTION 。2、遇到唯一键冲突如果在插入新记录时插入了一个与「已有的记录的主键或者唯一二级索引列值相同」的记录」不过可以有多条记录的唯一二级索引列的值同时为NULL这里不考虑这种情况此时插入就会失败然后对于这条记录加上了 S 型的锁。至于是行级锁的类型是记录锁还是 next-key 锁跟是主键冲突还是唯一二级索引冲突有关系。如果主键值重复当隔离级别为读已提交时插入新记录的事务会给已存在的主键值重复的聚簇索引记录添加 S 型记录锁。当隔离级别是可重复读默认隔离级别插入新记录的事务会给已存在的主键值重复的聚簇索引记录添加 S 型 next-key 锁。如果唯一二级索引列重复不论是哪个隔离级别插入新记录的事务都会给已存在的二级索引列值重复的二级索引记录添加 S 型 next-key 锁。对的没错即使是读已提交隔离级别也是加 next-key 锁这是读已提交隔离级别中为数不多的给记录添加间隙锁的场景。因为如果不添加间隙锁的话会让唯一二级索引中出现多条唯一二级索引列值相同的记录这就违背了 UNIQUE 的约束。下面举个唯一二级索引冲突的例子MySQL 8.0 版本事务隔离级别为可重复读默认隔离级别。t_order 表中的 order_no 字段为唯一二级索引并且已经存在 order_no 值为 1001 的记录此时事务 A插入了 order_no 为 1001 的记录就出现了报错。但是除了报错之外还做一个很重要的事情就是对 order_no 值为 1001 这条记录加上了 S 型的 next-key 锁。我们可以执行 select * from performance_schema.data_locks\G; 语句  确定事务加了什么类型的锁这里只关注在记录上加锁的类型。可以看到index_order 二级索引中的 1001LOCK_DATA 记录的锁类型为 S 型的 next-key 锁。注意这里 LOCK_TYPE 中的 RECORD 表示行级锁而不是记录锁的意思。如果是记录锁的话LOCK_MODE 会显示 S, REC_NOT_GAP。此时事务 B 执行了 select * from t_order where order_no 1001 for update;  就会阻塞因为这条语句想加 X 型的锁是与 S 型的锁是冲突的所以就会被阻塞。我们也可以从 performance_schema.data_locks 这个表中看到事务 B 的状态LOCK_STATUS是等待状态加锁的类型 X 型的记录锁LOCK_MODE: X,REC_NOT_GAP    。上面的案例是针对唯一二级索引重复而插入失败的场景。接下来分析两个事务执行过程中执行了相同的 insert 语句的场景。现在 t_order 表中只有这些数据order_no 为唯一二级索引。在隔离级别可重复读的情况下开启两个事务前后执行相同的  Insert 语句此时事务 B 的  Insert 语句会发生阻塞。两个事务的加锁过程事务 A 先插入 order_no 为 1006 的记录可以插入成功此时对应的唯一二级索引记录被「隐式锁」保护此时还没有实际的锁结构接着事务 B 也插入 order_no 为 1006 的记录由于事务 A 已经插入 order_no 值为 1006 的记录所以事务 B 在插入二级索引记录时会遇到重复的唯一二级索引列值此时事务 B 想获取一个 S 型 next-key 锁但是事务 A 并未提交事务 A 插入的 order_no 值为 1006 的记录上的「隐式锁」会变「显示锁」且锁类型为  X 型的记录锁所以事务 B 向获取 S 型 next-key 锁时会遇到锁冲突事务 B 进入阻塞状态。我们可以执行 select * from performance_schema.data_locks\G; 语句  确定事务加了什么类型的锁这里只关注在记录上加锁的类型。先看事务 A 对 order_no 为 1006 的记录加了什么锁从下图可以看到事务 A  对 order_no 为 1006 记录加上了类型为  X 型的记录锁注意这个是在执行事务 B 之后才产生的锁没执行事务 B 之前该记录还是隐式锁。然后看事务 B 想对 order_no 为 1006 的记录加什么锁从下图可以看到事务 B 想对 order_no 为 1006 的记录加 S 型的 next-key 锁但是由于事务 A 在该记录上持有了 X 型的记录锁这两个锁是冲突的所以导致事务 B 处于等待状态。从这个实验可以得知并发多个事务的时候第一个事务插入的记录并不会加锁而是会用隐式锁保护唯一二级索引的记录。但是当第一个事务还未提交的时候有其他事务插入了与第一个事务相同的记录第二个事务就会被阻塞因为此时第一事务插入的记录中的隐式锁会变为显示锁且类型是 X 型的记录锁而第二个事务是想对该记录加上 S 型的 next-key 锁X 型与 S 型的锁是冲突的所以导致第二个事务会等待直到第一个事务提交后释放了锁。如果 order_no 不是唯一二级索引那么两个事务前后执行相同的  Insert 语句是不会发生阻塞的就如前面的这个例子。如何避免死锁 死锁的四个必要条件互斥、占有且等待、不可强占用、循环等待。只要系统发生死锁这些条件必然成立但是只要破坏任意一个条件就死锁就不会成立。在数据库层面有两种策略通过「打破循环等待条件」来解除死锁状态设置事务等待锁的超时时间。当一个事务的等待时间超过该值后就对这个事务进行回滚于是锁就释放了另一个事务就可以继续执行了。在 InnoDB 中参数 innodb_lock_wait_timeout 是用来设置超时时间的默认值时 50 秒。当发生超时后就出现下面这个提示图片开启主动死锁检测。主动死锁检测在发现死锁后主动回滚死锁链条中的某一个事务让其他事务得以继续执行。将参数 innodb_deadlock_detect 设置为 on表示开启这个逻辑默认就开启。当检测到死锁后就会出现下面这个提示图片上面这个两种策略是「当有死锁发生时」的避免方式。我们可以回归业务的角度来预防死锁对订单做幂等性校验的目的是为了保证不会出现重复的订单那我们可以直接将 order_no 字段设置为唯一索引列利用它的唯一下来保证订单表不会出现重复的订单不过有一点不好的地方就是在我们插入一个已经存在的订单记录时就会抛出异常。参考资料《MySQL 是怎样运行的》http://mysql.taobao.org/monthly/2020/09/06/最后说个段子面试官: 解释下什么是死锁?应聘者: 你录用我,我就告诉你面试官: 你告诉我,我就录用你应聘者: 你录用我,我就告诉你面试官: 卧槽滚...........
http://www.zqtcl.cn/news/208949/

相关文章:

  • 北京国家建设部网站网站备案需要去哪里
  • 廊坊哪里能够做网站网站改版影响
  • 比较好的源码网站手机网站支付如何制作
  • 深圳做网站哪个公司好重庆工程造价信息2021
  • 做电商宠物带哪个网站最好最近一周的重大新闻
  • 做网站难度李沧网站建设电话
  • 六安建设网站网站图片最大尺寸是多少
  • 手机建网站步骤软件优速网站建设
  • 导购网站如何做免费推广用wordpress开发网站模板
  • 建立网站 英语wordpress字体加载
  • 株洲网站建设和制作wordpress 瑞课教育
  • 网站开发培训什么淘宝客网站备案
  • 提供网站制作公司用虚拟机做服务器搭建网站
  • 做煤层气的网站仅对wordpress自带主题有效
  • 优化网站关键词排名东莞网站设计报价
  • 建设厅网站总经济师是干什么的网络运营商电话
  • mvc5 网站开发之美专业企业建站价格
  • 水果电子商务网站建设规划书ipad做网站服务器
  • 网站模版自适应安卓软件开发培训
  • 网络网站建设10大指标开店装修话做那个网站找工人
  • dedecms网站的下载济南网站忧化
  • 深圳北站设计者亚洲国产中文域名查询
  • 有好的学网站建设的书吗龙岗网站建设服务
  • 建个注册页面网站做网站坚持多少年会有起色
  • 做网站是什么职位工商局网站查询入口
  • 做腰椎核磁证网站是 收 七如何做个盈利的网站
  • wordpress查看站点购物网站的后台做哪些东西
  • 文化馆为何需要建设自己的网站网站的建设教程
  • o2o网站策划京北网app下载
  • 公众号链接电影网站怎么做禁止wordpress保存修订版