1、超卖的解决方案
①、想到 悲观锁
select t.* from product where id for update; // 表锁 myISAM mysql 默认是 innoDB 作为存储引起, 它使用的是行锁。
update product set count = count -1 where id = #{id}; rollback; // 要么提交事务 commit; // 要么回滚事务
这里 用了 数据库的悲观锁, 这个条件下id 会被枷锁, 其他来执行的时候会一直等待, 但若是其他线程来请求过来,会一直 占有数据库连接, 导致 mysql 数据库连接数过多, 导致后面的mysql 的连接中断,或者超时。 使mysql 数据库崩溃。
②、 想到 乐观锁
select stock_count from product where id = #{id} update product set t.stock_count = t.stock_count -1 where id = #{id} and t.stock_count = #{stockCount};
cas 操作 执行 会影响 事务日志执行 过程中繁琐, 每次记录的日志都要 undo log,
或者 redo log,binlog,导致大量的这种日志文件。一定程度上影响MySQL 的性能
1.redo log通常是物理日志,记录的是数据页的物理修改,而不是某一行或某几行修改成怎样怎样,它用来恢复提交后的物理数据页(恢复数据页,且只能恢复到最后一次提交的位置)。
2.undo用来回滚行记录到某个版本。undo log一般是逻辑日志,根据每行记录进行记录
3、二进制日志(binlog): 1,用于复制,在主从复制中,从库利用主库上的binlog进行重播,实现主从同步。2,用于数据库的基于时间点的还原。
③、 sql 上进行 优化 执行
update product set stock_count = case when stock_count >= #{quantity} then sotck_count - #{quantity} else stock_count end where id = #{id}
2、少卖的解决方案
redis 进行 库存的增减
在redis 进行减库存 , 当 stock < 0 时, 若是 减失败了, 就需要加回来这个库存。不然就会出现少卖的情况,利用 redis 的 发布 订阅模式, 可以监听到库存的变化, 但是 redis 这边成功, 但是同步数据库的时候失败了, 就会导致数据库中实际还有库存,但redis 上 却没有库存了, 这样 怎么解决数据库 和 redis 之间的 强一致性, 但是做到实时的强一致性也很困难,毕竟redis 缓存到数据库之间 是有一定的时间差,这个 方案 也不是可取 的 , 有什么较好的补偿机制嘛? 回去想想???
redis 发布-订阅 模式
订阅,发布中监听减库存说一下。