国产亚洲精品福利在线无卡一,国产精久久一区二区三区,亚洲精品无码国模,精品久久久久久无码专区不卡

當(dāng)前位置: 首頁 > news >正文

那幾個網(wǎng)站可以做h5企業(yè)品牌推廣方案

那幾個網(wǎng)站可以做h5,企業(yè)品牌推廣方案,邢臺網(wǎng)站制作公司,焦作網(wǎng)站制作公司本博客為個人學(xué)習(xí)筆記,學(xué)習(xí)網(wǎng)站與詳細(xì)見:黑馬程序員Redis入門到實(shí)戰(zhàn) P50 - P54 目錄 優(yōu)惠卷秒殺下單功能實(shí)現(xiàn) 超賣問題 悲觀鎖與樂觀鎖 實(shí)現(xiàn)CAS法樂觀鎖 一人一單功能實(shí)現(xiàn) 代碼優(yōu)化 代碼細(xì)節(jié)分析 優(yōu)惠卷秒殺下單功能實(shí)現(xiàn) ? ? Controller層…

本博客為個人學(xué)習(xí)筆記,學(xué)習(xí)網(wǎng)站與詳細(xì)見:黑馬程序員Redis入門到實(shí)戰(zhàn)?P50?- P54?

目錄

優(yōu)惠卷秒殺下單功能實(shí)現(xiàn)

超賣問題

悲觀鎖與樂觀鎖

實(shí)現(xiàn)CAS法樂觀鎖

一人一單功能實(shí)現(xiàn)

代碼優(yōu)化?

代碼細(xì)節(jié)分析?


優(yōu)惠卷秒殺下單功能實(shí)現(xiàn)

?

?

Controller層代碼實(shí)現(xiàn)

@RestController
@RequestMapping("/voucher-order")
public class VoucherOrderController {@Resourceprivate IVoucherOrderService voucherOrderService;@PostMapping("seckill/{id}")public Result seckillVoucher(@PathVariable("id") Long voucherId) {return voucherOrderService.seckillVoucher(voucherId);}
}

Service層代碼實(shí)現(xiàn)

//接口類
public interface IVoucherOrderService extends IService<VoucherOrder> {Result seckillVoucher(Long voucherId);
}//實(shí)現(xiàn)類
@Service
public class VoucherOrderServiceImpl extends ServiceImpl<VoucherOrderMapper, VoucherOrder> implements IVoucherOrderService {@Resourceprivate ISeckillVoucherService seckillVoucherService;@Resourceprivate RedisIdWorker redisIdWorker;@Override@Transactionalpublic Result seckillVoucher(Long voucherId) {// 1.查詢優(yōu)惠券信息SeckillVoucher voucher = seckillVoucherService.getById(voucherId);// 2.根據(jù)優(yōu)惠券信息判斷秒殺是否開始if (voucher.getBeginTime().isAfter(LocalDateTime.now())) {// 秒殺尚未開始return Result.fail("秒殺尚未開始!");}// 3.判斷秒殺是否已經(jīng)結(jié)束if (voucher.getEndTime().isBefore(LocalDateTime.now())) {// 秒殺已經(jīng)結(jié)束return Result.fail("秒殺已經(jīng)結(jié)束!");}// 4.判斷庫存是否充足if (voucher.getStock() < 1) {// 庫存不足return Result.fail("庫存不足!");}// 5.扣減庫存boolean success = seckillVoucherService.update().setSql("stock = stock - 1").eq("voucher_id", voucherId).update();if (!success) {// 扣減失敗return Result.fail("庫存不足!");}// 6.創(chuàng)建訂單VoucherOrder voucherOrder = new VoucherOrder();// 6.1訂單idlong orderId = redisIdWorker.nextId("order");voucherOrder.setId(orderId);// 6.2用戶idLong userId = UserHolder.getUser().getId();voucherOrder.setUserId(userId);// 6.3代金卷idvoucherOrder.setVoucherId(voucherId);save(voucherOrder);// 7.返回訂單idreturn Result.ok(orderId);}
}

超賣問題

假設(shè)秒殺優(yōu)惠卷庫存為1,正常情況搶票邏輯如下圖所示。?

?

假設(shè)秒殺優(yōu)惠卷庫存為1,高并發(fā)情況搶票邏輯如下圖所示。?

?


悲觀鎖與樂觀鎖

?

由于悲觀鎖采用串行執(zhí)行線程的方式,因此性能劣于樂觀鎖。

樂觀鎖的關(guān)鍵是判斷之前查詢到的數(shù)據(jù)是否被修改過,常見的方式有以下兩種:

1.版本號法
為每種秒殺優(yōu)惠卷添加版本號屬性,每當(dāng)該優(yōu)惠卷的庫存被更改時(shí),令版本號也發(fā)生變化。因此只需要在查詢庫存的同時(shí)查詢并記錄版本號,在修改庫存時(shí),通過查詢當(dāng)前版本號并判斷其是否與先前記錄的版本號一致來判斷查詢到的庫存是否已經(jīng)被其他線程修改過。

?

2.CAS法(即版本號法的簡化,利用庫存代替版本號)

?


實(shí)現(xiàn)CAS法樂觀鎖

首先查詢秒殺優(yōu)惠卷信息并保存到變量voucher,當(dāng)判斷該優(yōu)惠卷可以被搶購后,在修改該優(yōu)惠卷庫存時(shí),需要滿足當(dāng)前優(yōu)惠卷庫存與voucher.getStock()相等的條件。
?

盡管添加了樂觀鎖,但在測試時(shí)發(fā)現(xiàn)用戶搶購優(yōu)惠卷的成功率過低。原因在于,在高并發(fā)的情況下,假設(shè)10個用戶同時(shí)搶購一張優(yōu)惠卷,那么只有一個用戶能夠搶購成功,其他用戶均搶購失敗。而在搶票的業(yè)務(wù)場景下,當(dāng)用戶同時(shí)進(jìn)行搶購時(shí),只要優(yōu)惠卷庫存大于0即可進(jìn)行搶購,因此只需修改判斷條件,在修改庫存時(shí),判斷當(dāng)前庫存是否大于0即可。

?


一人一單功能實(shí)現(xiàn)

?

修改Service層實(shí)現(xiàn)類中優(yōu)惠卷秒殺下單seckillVoucher方法,代碼(未優(yōu)化版本)如下:

@Override
@Transactional
public Result seckillVoucher(Long voucherId) {//1.查詢優(yōu)惠券SeckillVoucher voucher = seckillVoucherService.getById(voucherId);//2.判斷秒殺是否開始if (voucher.getBeginTime().isAfter(LocalDateTime.now())) {//尚未開始return Result.fail("秒殺尚未開始");}//3.判斷秒殺是否已經(jīng)結(jié)束if (voucher.getEndTime().isBefore(LocalDateTime.now())) {//尚未開始return Result.fail("秒殺已經(jīng)結(jié)束");}//4.判斷庫存是否充足if (voucher.getStock()<1) {//庫存不足return Result.fail("庫存不足");}//5.一人一單Long userId = UserHolder.getUser().getId();//5.1查詢訂單int count = query().eq("user_id", userId).eq("voucher_id", voucherId).count();//5.2判斷是否存在if(count>1){//用戶已經(jīng)購買過了return Result.fail("用戶已經(jīng)購買過一次");}//6.扣減庫存boolean success=seckillVoucherService.update().setSql("stock = stock - 1") //set stock =stock - 1.eq("voucher_id",voucherId).gt("stock",0)//where id=? and stock > 0.update();if(!success){return Result.fail("庫存不足!");}//7.創(chuàng)建訂單VoucherOrder voucherOrder = new VoucherOrder();//7.1訂單Idlong orderId = redisIdWorker.nextId("order");voucherOrder.setId(orderId);//7.2用戶IdvoucherOrder.setUserId(userId);//7.3代金券IdvoucherOrder.setVoucherId(voucherId);save(voucherOrder);//8.返回訂單IDreturn Result.ok(orderId);
}

代碼優(yōu)化?

存在的問題:盡管代碼經(jīng)過修改,但在高并發(fā)的情況下仍然存在問題,即單個用戶在同一刻多次下單,多個線程均查詢到count=0(該用戶未購買過當(dāng)前優(yōu)惠券),此時(shí)多個線程同時(shí)創(chuàng)建訂單,從而導(dǎo)致一人多單問題。

實(shí)現(xiàn):為實(shí)現(xiàn)一人一單功能,我們需要加鎖,相比超賣問題中每個線程只是對數(shù)據(jù)進(jìn)行修改,所以可以使用樂觀鎖,通過判斷數(shù)據(jù)值是否被修改來判斷其他線程是否已經(jīng)對當(dāng)前數(shù)據(jù)進(jìn)行操作。但一人多單的問題中,每個線程需要進(jìn)行添加數(shù)據(jù)而非修改數(shù)據(jù)的操作,即創(chuàng)建新的訂單,所以這種情況下,我們需要使用悲觀鎖。

優(yōu)化后的代碼如下所示:

@Service
public class VoucherOrderServiceImpl extends ServiceImpl<VoucherOrderMapper, VoucherOrder> implements IVoucherOrderService {@Resourceprivate ISeckillVoucherService seckillVoucherService;@Resourceprivate RedisIdWorker redisIdWorker;@Overridepublic Result seckillVoucher(Long voucherId) {// 1.查詢優(yōu)惠券信息SeckillVoucher voucher = seckillVoucherService.getById(voucherId);// 2.根據(jù)優(yōu)惠券信息判斷秒殺是否開始if (voucher.getBeginTime().isAfter(LocalDateTime.now())) {// 秒殺尚未開始return Result.fail("秒殺尚未開始!");}// 3.判斷秒殺是否已經(jīng)結(jié)束if (voucher.getEndTime().isBefore(LocalDateTime.now())) {// 秒殺已經(jīng)結(jié)束return Result.fail("秒殺已經(jīng)結(jié)束!");}// 4.判斷庫存是否充足if (voucher.getStock() < 1) {// 庫存不足return Result.fail("庫存不足!");}Long userId = UserHolder.getUser().getId();synchronized (userId.toString().intern()) {// 獲取當(dāng)前代理對象IVoucherOrderService proxy = (IVoucherOrderService) AopContext.currentProxy();return proxy.createVoucherOrder(voucherId);}}@Transactionalpublic synchronized Result createVoucherOrder(Long voucherId) {// 5.一人一單模式Long userId = UserHolder.getUser().getId();// 5.1查詢訂單int count = query().eq("user_id", userId).eq("voucher_id", voucherId).count();// 5.2判斷是否存在if (count > 0) {//用戶已經(jīng)購買過return Result.fail("用戶已經(jīng)購買過了");}// 6.扣減庫存boolean success = seckillVoucherService.update().setSql("stock = stock - 1")  //使用MP,設(shè)置sql語句.eq("voucher_id", voucherId).gt("stock", 0).update();if (!success) {// 扣減失敗return Result.fail("庫存不足!");}// 7.創(chuàng)建訂單VoucherOrder voucherOrder = new VoucherOrder();// 7.1獲取訂單全局idlong orderId = redisIdWorker.nextId("order");voucherOrder.setId(orderId);// 7.2用戶idvoucherOrder.setUserId(userId);// 7.3代金卷idvoucherOrder.setVoucherId(voucherId);save(voucherOrder);// 8.返回訂單idreturn Result.ok(orderId);}
}

代碼細(xì)節(jié)分析?

有以下幾個細(xì)節(jié)我們需要特別注意

1. 首先,我們將查詢、判斷、創(chuàng)建訂單等過程封裝成createVoucherOrder方法,但是我們并不能直接對這個方法加鎖,如果對這個方法加鎖的話將導(dǎo)致創(chuàng)建訂單的業(yè)務(wù)是串行執(zhí)行的,在高并發(fā)多用戶的情況下,性能會很差。

2. 因?yàn)槭且蝗艘粏喂δ?#xff0c;我們需要做的是對同一個用戶創(chuàng)建訂單的流程進(jìn)行加鎖,所以我們根據(jù)用戶ID來加鎖。我們?yōu)橄嗤挠脩鬒D配置一把鎖,從而將鎖的范圍縮小,因此我們將createVoucherOrder方法進(jìn)行修改,如下所示。

3. 然而,我們需要確保synchronized()傳入的參數(shù)對象是相同的,synchronized鎖才能起作用。因此我們不傳入查詢得到的userId對象,因?yàn)槲覀兠看尾樵兒蠖紩x值給新的userId對象,這樣會導(dǎo)致傳入synchronized()的參數(shù)始終不是同一個對象,因此我們采用的是synchronized(userId.toString())。

4.但是,如果我們直接使用userId.toString() 方法,拿到的對象實(shí)際上是不同的,toString() 的底層邏輯是new出一個新對象,因此我們需要使用intern()方法,該方法是從常量池中拿到數(shù)據(jù),能確保我們每次取得的對象都是相同的。得到的代碼如下所示。

@Transactional
//將創(chuàng)建訂單封裝成一個方法
public  Result createVoucherOrder(Long voucherId) {//獲取用戶IdLong userId = UserHolder.getUser().getId();synchronized(userId.toString().intern()) {查詢、判斷、創(chuàng)建訂單等流程...}
}//錯誤情況:synchronized(userId.toString())

5.由于我們是在方法里面加鎖,因此代碼的邏輯是先釋放鎖,再提交事務(wù),因此在高并發(fā)的環(huán)境下可能會出現(xiàn)安全問題(即釋放鎖后,提交事務(wù)還未完成,其他線程又進(jìn)來了)。所以我們應(yīng)該先提交事務(wù),再釋放鎖。因此,我們應(yīng)該在方法外加鎖,代碼如下。

@Override
public Result seckillVoucher(Long voucherId) {...Long userId = UserHolder.getUser().getId();synchronized (userId.toString().intern()) {return createVoucherOrder(voucherId);}
}

6.在以上代碼中,我們調(diào)用createVoucherOrder方法,其實(shí)是通過this.的方式調(diào)用的,而this代表的是當(dāng)前VoucherOrderServiceImpl對象,并不是createVoucherOrder的代理對象,因此事務(wù)是不生效的。要想讓事務(wù)生效,我們需要利用代理對象調(diào)用createVoucherOrder方法,才能使事務(wù)生效,代碼如下。

@Override
public Result seckillVoucher(Long voucherId) {...Long userId = UserHolder.getUser().getId();synchronized (userId.toString().intern()) {// 獲取當(dāng)前代理對象IVoucherOrderService proxy = (IVoucherOrderService) AopContext.currentProxy();return proxy.createVoucherOrder(voucherId);}
}

此外,我們還需做以下三步。
1.添加動態(tài)代理依賴

<dependency><groupId>org.aspectj</groupId><artifactId>aspectjweaver</artifactId>
</dependency>

2.在接口中添加createVoucherOrder(Long voucherId);?

public interface IVoucherOrderService extends IService<VoucherOrder> {Result seckillVoucher(Long voucherId);Result createVoucherOrder(Long voucherId);
}

3.在啟動類中添加注解,暴露該代理對象

@EnableAspectJAutoProxy(exposeProxy = true)
@MapperScan("com.hmdp.mapper")
@SpringBootApplication
public class HmDianPingApplication {public static void main(String[] args) {SpringApplication.run(HmDianPingApplication.class, args);}}

http://m.aloenet.com.cn/news/37579.html

相關(guān)文章:

  • 為什么網(wǎng)站打不開首頁深圳博惠seo
  • 去哪里學(xué)做網(wǎng)站app網(wǎng)站建設(shè)的意義和作用
  • 修改wordpress主題字體大小seo網(wǎng)站推廣是什么意思
  • 濱州做網(wǎng)站的公司廣告門
  • 新開傳奇網(wǎng)站曾勁松線下推廣方式都有哪些
  • 網(wǎng)站開發(fā) 零基礎(chǔ)營銷號
  • 凡科網(wǎng)站是什么做的十大免費(fèi)引流平臺
  • 南京專業(yè)做網(wǎng)站的公司重慶二級站seo整站優(yōu)化排名
  • 去哪里找空間做網(wǎng)站搜索引擎營銷的分類
  • 餐飲門戶網(wǎng)站 方案怎么做百度競價(jià)開戶費(fèi)用
  • 石家莊做網(wǎng)站建設(shè)公司外鏈查詢
  • 尋找移動網(wǎng)站建設(shè)開魯網(wǎng)站seo不用下載
  • 小程序有什么用武漢seo管理
  • 做項(xiàng)目掙錢的網(wǎng)站seo快速排名軟件品牌
  • wordpress 熱門用戶網(wǎng)頁優(yōu)化包括什么
  • 移動端網(wǎng)站模板怎么做網(wǎng)絡(luò)推廣員的日常工作
  • 網(wǎng)頁的網(wǎng)站建設(shè)在哪里搜索引擎站長平臺
  • 微網(wǎng)站左側(cè)隱藏導(dǎo)航菜單鄭州網(wǎng)絡(luò)營銷策劃
  • 湖北潛江資訊網(wǎng)紹興seo計(jì)費(fèi)管理
  • 一流的網(wǎng)站建設(shè)哪家好最近的新聞大事
  • 麗水連都區(qū)建設(shè)局網(wǎng)站網(wǎng)絡(luò)推廣運(yùn)營推廣
  • 手機(jī)網(wǎng)站微信登陸推廣是什么意思
  • 東莞響應(yīng)式網(wǎng)站建設(shè)抖音排名優(yōu)化
  • 做網(wǎng)站編輯我能力得到提升cps推廣接單平臺
  • 免費(fèi)推廣做產(chǎn)品的網(wǎng)站廣州新聞24小時(shí)爆料熱線
  • 福建咨詢網(wǎng)站建設(shè)商家站長之家端口掃描
  • 什么是網(wǎng)絡(luò)營銷行為分析滎陽seo推廣
  • 電腦如何創(chuàng)建網(wǎng)頁優(yōu)化落實(shí)疫情防控新十條
  • 網(wǎng)站管理建設(shè)的總結(jié)中層管理者培訓(xùn)課程有哪些
  • 廣州市網(wǎng)站開發(fā)搜索引擎有哪些分類