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

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

自己做電影網(wǎng)站可以賺錢嗎新媒體運(yùn)營培訓(xùn)班

自己做電影網(wǎng)站可以賺錢嗎,新媒體運(yùn)營培訓(xùn)班,網(wǎng)站建設(shè)優(yōu)化外包,做古風(fēng)頭像的網(wǎng)站全局唯一ID 全局唯一ID生成策略: UUIDRedis自增snowflake算法數(shù)據(jù)庫自增 Redis自增ID策略:每天一個key,方便統(tǒng)計訂單量ID構(gòu)造是 時間戳 計數(shù)器 Component public class RedisIdWorker {// 2024的第一時刻private static final long BEGIN…

全局唯一ID

全局唯一ID生成策略:

  • UUID
  • Redis自增
  • snowflake算法
  • 數(shù)據(jù)庫自增
    Redis自增ID策略:
  • 每天一個key,方便統(tǒng)計訂單量
  • ID構(gòu)造是 時間戳 + 計數(shù)器
@Component
public class RedisIdWorker {// 2024的第一時刻private static final long BEGIN_TIMESTAMP = 1704067200L;private static final int COUNT_BITS = 32;private final StringRedisTemplate stringRedisTemplate;public RedisIdWorker(StringRedisTemplate stringRedisTemplate) {this.stringRedisTemplate = stringRedisTemplate;}public long nextId(String keyPrefix){// 1. 獲取當(dāng)前時間戳LocalDateTime now = LocalDateTime.now();long nowSecond = now.toEpochSecond(ZoneOffset.UTC);long timeStamp = nowSecond - BEGIN_TIMESTAMP;// 2. 獲取序列號// 2.1 獲取當(dāng)天日期,精確到天String date = now.format(DateTimeFormatter.ofPattern("yyyy:MM:dd"));// 2.2 自增Long count = stringRedisTemplate.opsForValue().increment("icr:" + keyPrefix + ":" + date);// 3. 拼接成IDreturn timeStamp << COUNT_BITS | count;}}

超賣問題

在處理大量請求時,可能會出現(xiàn)超賣問題。
可以通過加鎖解決。
在這里插入圖片描述
這里采用的是樂觀鎖。

一人一單

該任務(wù)需要每名用戶只能搶到一張優(yōu)惠券。
同時還要考慮到后端部署在多個服務(wù)器上可能會出現(xiàn)的異常,此時需要使用分布式鎖進(jìn)行解決。
這里的分布式鎖基于Redis實現(xiàn)。

基于Redis的分布式鎖實現(xiàn)思路

基于Redis的分布式鎖實現(xiàn)思路:

  • 利用set nx ex獲取鎖,并設(shè)置過期時間,保存線程標(biāo)示
  • 釋放鎖時先判斷線程標(biāo)示是否與自己一致,一致則刪除鎖

特性:

  • 利用set nx滿足互斥性
  • 利用set ex保證故障時鎖依然能釋放,避免死鎖,提高安全性
  • 利用Redis集群保證高可用和高并發(fā)特性

使用Redis優(yōu)化秒殺

這里將庫存判斷與一人一單的校驗使用Redis完成。
具體流程為:

  • 新增秒殺優(yōu)惠券的同時,將優(yōu)惠券信息保存到Redis中
  • 基于Lua腳本,判斷秒殺庫存、一人一單,決定用戶是否搶購成功
  • 如果搶購成功,將優(yōu)惠券id和用戶id封裝后存入阻塞隊列
  • 開啟線程任務(wù),不斷從阻塞隊列中獲取信息,實現(xiàn)異步下單功能
    這里的阻塞隊列是基于Stream的消息隊列
    STREAM類型消息隊列的XREADGROUP命令特點
  • 消息可回溯
  • 可以多消費者爭搶消息,加快消費速度
  • 可以阻塞讀取
  • 沒有消息漏讀的風(fēng)險
  • 有消息確認(rèn)機(jī)制,保證消息至少被消費一次
    在這里插入圖片描述
    新增秒殺優(yōu)惠券的同時,將優(yōu)惠券信息保存到Redis中
    @Override@Transactionalpublic void addSeckillVoucher(Voucher voucher) {// 保存優(yōu)惠券save(voucher);// 保存秒殺信息SeckillVoucher seckillVoucher = new SeckillVoucher();seckillVoucher.setVoucherId(voucher.getId());seckillVoucher.setStock(voucher.getStock());seckillVoucher.setBeginTime(voucher.getBeginTime());seckillVoucher.setEndTime(voucher.getEndTime());seckillVoucherService.save(seckillVoucher);// 保存優(yōu)惠券至RedisstringRedisTemplate.opsForValue().set(RedisConstants.SECKILL_STOCK_KEY +voucher.getId(), voucher.getStock().toString());}

基于Lua腳本,判斷秒殺庫存、一人一單,決定用戶是否搶購成功

-- 1.參數(shù)列表
local voucherId = ARGV[1]
local userId = ARGV[2]
local orderId = ARGV[3]
-- 2. 數(shù)據(jù)key
local stockKey = "seckill:stock:" .. voucherId
local orderKey = "seckill:order:" .. voucherId-- 3. 判斷庫存是否充足
if tonumber(redis.call('get', stockKey) )< 1 then-- 庫存不足return 1
end-- 4. 判斷用戶是否已經(jīng)搶購過
if redis.call('sismember', orderKey, userId) == 1 then-- 已經(jīng)搶購過return 2
end-- 5. 減庫存
redis.call('incrby', stockKey, -1)
-- 6. 記錄用戶搶購信息
redis.call('sadd', orderKey, userId)redis.call('xadd', "stream.orders", "*", "userId", userId,  "voucherId", voucherId,"id", orderId)
return 0

異步下單
LUA腳本

-- 1.參數(shù)列表
local voucherId = ARGV[1]
local userId = ARGV[2]
local orderId = ARGV[3]
-- 2. 數(shù)據(jù)key
local stockKey = "seckill:stock:" .. voucherId
local orderKey = "seckill:order:" .. voucherId-- 3. 判斷庫存是否充足
if tonumber(redis.call('get', stockKey) )< 1 then-- 庫存不足return 1
end-- 4. 判斷用戶是否已經(jīng)搶購過
if redis.call('sismember', orderKey, userId) == 1 then-- 已經(jīng)搶購過return 2
end-- 5. 減庫存
redis.call('incrby', stockKey, -1)
-- 6. 記錄用戶搶購信息
redis.call('sadd', orderKey, userId)redis.call('xadd', "stream.orders", "*", "userId", userId,  "voucherId", voucherId,"id", orderId)
return 0

從消息隊列取出,處理代碼

@Slf4j
@Service
public class VoucherOrderServiceImpl extends ServiceImpl<VoucherOrderMapper, VoucherOrder> implements IVoucherOrderService {@Resourceprivate ISeckillVoucherService seckillVoucherService;@Resourceprivate RedisIdWorker redisIdWorker;@Resourceprivate StringRedisTemplate stringRedisTemplate;@Resourceprivate RedissonClient redissonClient;private IVoucherOrderService proxy;// 靜態(tài)代碼塊加載Lua腳本private static final DefaultRedisScript<Long> SECKILL_SCRIPT;static {SECKILL_SCRIPT = new DefaultRedisScript<>();SECKILL_SCRIPT.setLocation(new ClassPathResource("seckill.lua"));SECKILL_SCRIPT.setResultType(Long.class);}//    private BlockingQueue<VoucherOrder> orderTasks = new ArrayBlockingQueue<>(1024*1024);// 線程池private static final ExecutorService SECKILL_ORDER_EXECUTOR = Executors.newSingleThreadExecutor();@PostConstruct// 完成類的construct即執(zhí)行下面的函數(shù)public void init() {// 交給線程池做SECKILL_ORDER_EXECUTOR.submit(new VoucherOrderHandler());}String queueName = "stream.orders";// 消費線程private class VoucherOrderHandler implements Runnable {@Overridepublic void run() {while (true) {try {// 4.1從消息隊列中取出訂單 xreadgroupnngroup g1 c1 count 1 block 200 streams streams.order >List<MapRecord<String, Object, Object>> list = stringRedisTemplate.opsForStream().read(Consumer.from("g1", "c1"),StreamReadOptions.empty().count(1).block(Duration.ofSeconds(2)),StreamOffset.create(queueName, ReadOffset.lastConsumed()));// 判斷是否成功// 沒有if (list == null || list.isEmpty()) {continue;}// 有// 4.2創(chuàng)建訂單,解析消息MapRecord<String, Object, Object> record = list.get(0);Map<Object, Object> value = record.getValue();VoucherOrder voucherOrder = BeanUtil.fillBeanWithMap(value, new VoucherOrder(), true);handleVoucherOrder(voucherOrder);// ACK確認(rèn)stringRedisTemplate.opsForStream().acknowledge(queueName, "g1", record.getId());} catch (Exception e) {log.error("訂單處理失敗", e);handlePendingList();}}}}private void handlePendingList() {while (true) {try {// 4.1從消息隊列中取出訂單 xreadgroupnngroup g1 c1 count 1 block 200 streams streams.order >List<MapRecord<String, Object, Object>> list = stringRedisTemplate.opsForStream().read(Consumer.from("g1", "c1"),StreamReadOptions.empty().count(1),StreamOffset.create(queueName, ReadOffset.from("0")));// 判斷是否成功// 沒有if (list == null || list.isEmpty()) {// pendingList 沒有消息break;}// 有// 4.2創(chuàng)建訂單,解析消息MapRecord<String, Object, Object> record = list.get(0);Map<Object, Object> value = record.getValue();VoucherOrder voucherOrder = BeanUtil.fillBeanWithMap(value, new VoucherOrder(), true);handleVoucherOrder(voucherOrder);// ACK確認(rèn)stringRedisTemplate.opsForStream().acknowledge(queueName, "g1", record.getId());} catch (Exception e) {log.error("訂單處理失敗", e);try {Thread.sleep(200);} catch (InterruptedException ex) {throw new RuntimeException(ex);}}}}private void handleVoucherOrder(VoucherOrder voucherOrder) {// 因為為子線程,userId只能從數(shù)據(jù)中取Long userId = voucherOrder.getUserId();RLock lock = redissonClient.getLock("order:" + userId);boolean isLock = lock.tryLock();if (!isLock) {log.error("重復(fù)搶購");return ;}try {proxy.createVoucherOrder(voucherOrder);return;} finally {lock.unlock();}}

創(chuàng)建訂單

    @Transactionalpublic Result createVoucherOrder(VoucherOrder voucherOrder) {// 4.一人一單Long userId = voucherOrder.getUserId();// 4.1 查詢訂單int count = query().eq("user_id", userId).eq("voucher_id", voucherOrder.getVoucherId()).count();if (count > 0) {return Result.fail("每人限購一張");}// 4.是// 4.1扣減庫存,基于樂觀鎖boolean success = seckillVoucherService.update().setSql("stock=stock-1").eq("voucher_id", voucherOrder.getVoucherId()).gt("stock", 0).update();if (!success) {return Result.fail("庫存不足");}//4.2創(chuàng)建訂單save(voucherOrder);//4.3返回訂單idreturn Result.ok(voucherOrder.getId());}
    @Overridepublic Result seckillVoucher(Long voucherId) {Long userId = UserHolder.getUser().getId();// 0. 生成訂單idlong orderId = redisIdWorker.nextId("order");// 1. 執(zhí)行l(wèi)ua腳本Long result = stringRedisTemplate.execute(SECKILL_SCRIPT,Collections.emptyList(),voucherId.toString(), userId.toString(), String.valueOf(orderId));// 2. 結(jié)果是否為0int r = result.intValue();// 2.1 不為0if (r!=0) {return Result.fail(r == 1 ? "庫存不足" : "不能重復(fù)搶購");}// 注解底層基于aop實現(xiàn),需要獲得代理對象,進(jìn)行執(zhí)行proxy = (IVoucherOrderService)AopContext.currentProxy();// 3. 返回結(jié)果訂單idreturn Result.ok(orderId);}
http://aloenet.com.cn/news/45943.html

相關(guān)文章:

  • 懶人做圖網(wǎng)站江門seo
  • 國外家譜網(wǎng)站的建設(shè)關(guān)鍵詞排名怎么做上首頁
  • 四川成都最新新聞事件今天深圳谷歌seo推廣
  • 自己的服務(wù)器做網(wǎng)站優(yōu)速網(wǎng)站建設(shè)優(yōu)化seo
  • web app 和網(wǎng)站的區(qū)別企業(yè)郵箱賬號
  • 定制做網(wǎng)站百度網(wǎng)絡(luò)科技有限公司
  • 免費做網(wǎng)站的網(wǎng)址有哪些網(wǎng)絡(luò)整合營銷4i原則
  • 微信小網(wǎng)站怎么做百度競價廣告推廣
  • 盱眙在仕德偉做網(wǎng)站的有幾家如何進(jìn)行品牌營銷
  • 焦作市網(wǎng)站建設(shè)科技推廣方法有哪幾種
  • 寧波外貿(mào)網(wǎng)站推廣今日頭條重大消息
  • 網(wǎng)站建設(shè)需要哪些技能天津seo顧問
  • ecshop源碼南京seo報價
  • 鄭州網(wǎng)站高端設(shè)計百度網(wǎng)站打不開
  • 動態(tài)網(wǎng)站開發(fā)教案xp優(yōu)化大師
  • 網(wǎng)站建設(shè)付款方式河南百度seo
  • 百度推廣網(wǎng)站怎么做網(wǎng)站策劃方案案例
  • asp網(wǎng)站建設(shè)下載青島百度推廣seo價格
  • 必應(yīng)網(wǎng)站收錄在哪seo推廣顧問
  • 做網(wǎng)站用模板百度競價廣告怎么投放
  • 做移動互聯(lián)網(wǎng)站點哪些店鋪適合交換友情鏈接
  • 網(wǎng)站專題模板下載上海優(yōu)化網(wǎng)站公司哪家好
  • 建網(wǎng)站怎么做報分系統(tǒng)網(wǎng)絡(luò)推廣公司有多少家
  • 怎樣做校園網(wǎng)站推廣手游推廣渠道和推廣方式
  • 海南省人民政府網(wǎng)站官網(wǎng)寧波百度快照優(yōu)化排名
  • 17素材網(wǎng)官網(wǎng)蘇州seo
  • 公安局網(wǎng)站建設(shè)營銷策略
  • 社交網(wǎng)站建設(shè)教程愛網(wǎng)
  • 南陽專業(yè)做網(wǎng)站公司seo技術(shù)培訓(xùn)茂名
  • 做網(wǎng)站老師全自動引流推廣軟件下載