方案一:事务+数据库行锁,行锁是一种悲观锁
行级锁定是目前各大数据库管理软件所实现的锁定颗粒度最小的,所以发生锁定资源争用的概率也最小,能够给予应用程序尽可能大的并发处理能力而提高一些需要高并发应用系统的整体性能。
但是由于锁定资源的颗粒度很小,所以每次获取锁和释放锁消耗的资源也更多,带来的消耗自然也就更大了。此外,行级锁定也最容易发生死锁。
1.什么叫做悲观锁呢?
1.1 顾名思义,就是很悲观,每次去拿数据的时候都认为别人会修改,所以每次在拿数据的时候都会上锁,先把坑占了,防止被人抢用
1.2 先上锁,在更新数据,完成后释放锁
1.3 适合多写和写冲突比较多的场景
2.如何在程序中加入行锁呢?
2.1 开启数据库事务
2.2 在数据库事务锁定中操作行
select * from t where id=? **for update**
select 语句后面加入了for update 关键字会等待行锁释放后在返回查询结果集,并发线程进行数据更新的时候遇到for update 关键字就会进行 阻塞 等待 直到行锁释放
2.3 在事务中对库存、金额字段进行扣减,然后进行数据更新
update t set number=? where id=?
2.4 提交事务,释放行锁
优点:
稳定可靠,不会出现超卖现象
缺点:1.需要查询和重新计算,性能差,锁等待阻塞
2.锁堵塞等待会导致客户端延迟或者超时
3.事务重试会增加网络和系统的开销
方案二 超卖现象的优化 ,数据库字段的优化无符号类型
unsigned 是表示无符号数据类型,非负数
1.将库存字段设为无符号整型
Create table red_envelope_goods(
id int(11) UNSIGNED PRIMARY key not null auto_increment,
num int(11) UNSIGNED ,
money DECIMAL(10,3) UNSIGNED
) ENGINE=INNODB DEFAULT charset=utf8;
方案三 超卖现象-乐观锁
乐观锁假设认为数据一般情况下不会造成冲突,所以在数据进行提交更新的时候,才会正式对数据的冲突与否进行检测
乐观锁的实现方式:
使用数据版本(Version)记录机制实现,这是乐观锁最常用的一种实现方式。何谓数据版本?即为数据增加一个版本标识,一般是通过为数据库表增加一个数字类型的
“version”
字段来实现。当读取数据时,将version字段的值一同读出,数据每更新一次,对此version值加一。当我们提交更新的时候,判断数据库表对应记录的当前版本信息与第一次取出来的version值进行比对,如果数据库表当前版本号与第一次取出来的version值相等,则予以更新,否则认为是过期数据
乐观锁
1.假设数据不会被他人修改,自己操作时验证一哈数据的版本
2 先比较在更新
3适合写入比较少的场景
- case 语句
2.where 语句