超卖和重复下单
解决高并发重复下单
mysql的索引机制
利用mysql的索引机制来解决重复下单的问题
使用联合索引,类型用unique,那么指定的联合索引字段只要和某一行的指定字段重复就插入失败,从而能对此次的重复下单业务进行回滚操作。
如果只设置一个字段,那么只要该字段重复就不能执行插入操作。
索引理解:使用InnoDB引擎的mysql,是有一个行级锁的机制在里面的。
1、InnoDB行锁是通过给索引项加锁来实现的,这一点mysql和 oracle不同;
2、InnoDB这种行级锁决定,只有通过索引条件来检索数据,才能使用行级锁,否则, 直接使用表级锁。
特别注意: 使用行级锁一定要使用索引
行级锁解释:
其实很简单,啰嗦这么多,怕自己忘记。
顾名思义,行锁就是针对数据表中行记录的锁。这很好理解,比如事务 A 更新了一行,而这时候事务 B 也要更新同一行,则必须等事务 A 的操作完成后才能进行更新。事务A还没有commit提交完成之前,事务B的sql语句是一直被阻塞的状态。
行级锁就是:无论有多少线程执行sql插入操作,因为有行级锁,所以都得一个个来,第一个执行sql操作还没结束的话,后面的都得乖乖等待,此时后面的他们都是属于阻塞状态。
只要有数据插入失败,那么整个方法都会回滚,前面即使扣库存成功也能回滚
解决高并发超卖问题
思路:
修改sql的where判断,增加判断库存是否为0,如果库存为0了,那么update修改库存数据的那条sql就会因为判断不通过而不会执行修改,修改失败的时候(其实也可以理解为修改成功0条数据),也是通过innodb的行级锁机制,在秒杀方法执行减库存的时候,因为遇到修改库存失败而进行回滚操作。再抛个异常就可以了。
代码:
如图:
库存为0就减不了了,所以就不存在超卖的问题了。
测试:
操作:
1、清空t_order_info和t_order_info表,t_seckill_goods的stock_count数为10
2、清空 wolfcode_member 数据库的 t_user表,重新通过 http://localhost:8090/initData 方法生成500个用户,为的就是要redis里面有这500个用户的数据,调用initData方法前先把tokens.txt清除掉旧的token数据。
成功:
总结:
解决重复下单总结:
**1、解决重复下单:**从mysql入手,只需要通过使用 联合索引 + innodb的行级锁机制,在插入新一条数据的时候,如果联合索引中指定字段与旧的一条数据重复,那么就会插入失败,然后秒杀方法进行回滚。
这就解决了重复下单的问题。
解决超卖问题总结:
2、解决超卖:也是从mysql入手,通过修改sql的where条件,判断库存是否为0,如果为0就不再修改库存。当库存为0(update失败后),那么抛个异常,使秒杀方法进行回滚。
这就解决了超卖的问题。