黑马点评03一人一单

实战篇-07.优惠券秒杀-实现一人一单功能_哔哩哔哩_bilibili

1.之前的问题

虽然解决了超卖问题,但是无法保证一人只能买一张,容易发生黄牛行为。

2.解决方案

2.1订单查询:判断该用户是否已下单

在库存判断之前,判断用户id和优惠券id是否已经存在,如果存在就停止

但是因为先判断再执行,仍然会出现多线程穿插执行的情况。

为了解决多线程冲突,要加锁

乐观锁因为要根据修改判断版本号,所以只能适用于更新情况。对于多线程查询情况只能用悲观锁。

2.2对订单查询加悲观锁sychronized锁

但是没必要对整个方法加锁,所以这里把后面5,6,7封装到createVoucherOrder方法里。

2.2.1 

如果对整个方法加sychronized锁,那么锁监视器是this(当前对象),那么不管什么用户来,监视器都是this,相当于串行执行了,性能差。

2.2.2

一人一单是同一个用户来造成的并发安全问题,所以需要用某个用户的特征作为锁监视器,锁住某个用户的并发操作,而不影响不同用户之间的操作。

toString返回值会new一个String,所以每次都是新对象,即便是同一个用户,每次的锁监视器都不一样。

 

2.2.3

所以需要intern()方法,相当于只要内容一样,就返回常量池中那个String的地址,而不会返回toString new的地址。

这样就能保证只要用户id一样,字符串内容一样,就能从常量池获取一样的引用返回值,从而保证同一用户锁监视器的一致性。

2.2.4释放锁的时机

因为上述代码锁只到return,而spring会在return之后函数结束之后才提交数据库事务,因此在锁释放到事务提交期间仍有并发问题,所以要把锁括住整个业务函数。

基本解决一人一单问题

2.2.5事务失效

spring 事务失效的 12 种场景_spring 截获duplicatekeyexception 不抛异常-CSDN博客

Spring同一个Service类非事务方法调用事务方法事务失效解决方案-CSDN博客 

java代理对象_java 什么是代理对象-CSDN博客 

但是该代码调用事务业务的时候的this不能处理事务,所以有事务失效的可能。所以要拿当前对象的代理对象

 

猜你喜欢

转载自blog.csdn.net/m0_50973548/article/details/135006574