Seckill core design (reduce inventory part) - anti-oversold and high concurrency


http://f.dataguru.cn/thread-485176-1-1.html
(Source: Alchemy into Gold)
from: http://www.tuicool.com/articles/Bfa63e6

              Staticization of product details page, varnish acceleration , the second-kill commodity library independent deployment server will be omitted. Only discuss the optimization of the inventory part. The optimization of the
      mysql configuration level can refer to my article    "A little experience about the performance optimization of the mysql innodb engine",  
  which focuses on the database level.
  2 tables:
  the first one: the judgment table (buy_record), has the user killed the product
  field: id, uid, goods_id, addtime
  The second table: the goods table goods
  field: goods_id goods_num
      Scheme 1:  
  start transaction;
  select id from buy_record where uid=$uid and goods_id=$goods_id;
  if (the result is not empty)
      throw an exception and roll back.
  insert into buy_record. . .
  if (number of affected rows <= 0)
          throws an exception and rolls back. . .  
  select goods_num from goods where goods_id=$good_id;
  if (stock<=0)
          throw an exception and roll back. . .  
  update goods set goods_num=goods_num-1 where goods_id=$goods_id;
  if (number of affected rows <= 0)
      This method almost inevitably leads to overselling under high concurrency. When the inventory is 1, multiple users     select goods_num from goods where goods_id=$good_id at the same time; at this time, the inventory is just greater than 0, and it must be reduced to less than 0 when the update operation is performed. A similar problem occurs.   
      Solution 2:  
  start transaction;
      select id from buy_record where uid=$uid and goods_id=$goods_id          for update        ;  
  if (the result is not empty)
      throw an exception and roll back.
  insert into buy_record. . .
  if (number of affected rows <= 0)
      throws an exception and rolls back. . .
      select goods_num from goods where goods_id=$good_id    for update    ;  
  if(stock<=0)
      throws an exception and rolls back. . .
      update goods set goods_num=goods_num-1 where goods_id=$goods_id ;  
  if (number of affected rows <= 0)
      throw an exception and roll back. . .
      This method can effectively prevent overselling, but an exclusive lock is added to each select, and each select operation will be blocked     , and the concurrency performance will be greatly reduced.   
            Solution 3: Add a unique index to (uid, goods_id)! !      
  start transaction;
      insert into buy_record. . .  
  If (unique index error?)
      throws an exception, seconds have passed, rollback. . .
            update goods set goods_num=goods_num-1 where goods_id=$goods_id and goods_num>0 ;      
  if (number of affected rows<=0)
      throws an exception, the goods are finished in seconds and rollback. . .
      This method perfectly solves the problem of low concurrency caused by overselling and select exclusive locks, and reduces 4 SQLs to 2 SQL statements. Greatly improve performance  

Guess you like

Origin http://10.200.1.11:23101/article/api/json?id=326941058&siteId=291194637