中文亚洲精品无码_熟女乱子伦免费_人人超碰人人爱国产_亚洲熟妇女综合网

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

社保網(wǎng)站是每月1-6號(hào)都是在建設(shè)中的嗎發(fā)外鏈軟件

社保網(wǎng)站是每月1-6號(hào)都是在建設(shè)中的嗎,發(fā)外鏈軟件,給別人做的網(wǎng)站涉及到詐騙,wordpress手機(jī)登錄跳轉(zhuǎn)頁(yè)面模板文章目錄 什么是緩存?添加Redis緩存店鋪類(lèi)型查詢(xún)業(yè)務(wù)添加緩存練習(xí)題 緩存更新策略給查詢(xún)商鋪的緩存添加超時(shí)剔除和主動(dòng)更新的策略 緩存穿透緩存空對(duì)象布隆過(guò)濾 緩存雪崩解決方案 緩存擊穿解決方案基于互斥鎖方式解決緩存擊穿問(wèn)題基于邏輯過(guò)期的方式解決緩存擊穿問(wèn)題…

文章目錄

  • 什么是緩存?
  • 添加Redis緩存
    • 店鋪類(lèi)型查詢(xún)業(yè)務(wù)添加緩存練習(xí)題
  • 緩存更新策略
    • 給查詢(xún)商鋪的緩存添加超時(shí)剔除和主動(dòng)更新的策略
  • 緩存穿透
    • 緩存空對(duì)象
    • 布隆過(guò)濾
  • 緩存雪崩
    • 解決方案
  • 緩存擊穿
    • 解決方案
    • 基于互斥鎖方式解決緩存擊穿問(wèn)題
    • 基于邏輯過(guò)期的方式解決緩存擊穿問(wèn)題
  • 緩存工具封裝

什么是緩存?

在這里插入圖片描述

緩存也要考慮成本的問(wèn)題,不是隨便用的
在這里插入圖片描述

添加Redis緩存

在這里插入圖片描述
在這里插入圖片描述

@Overridepublic Result queryById(Long id) {String redisKey = RedisConstants.CACHE_SHOP_KEY + id;// 1. 從redis查詢(xún)商鋪緩存String shopJson = stringRedisTemplate.opsForValue().get(redisKey);// 2. 判讀是否存在if(StrUtil.isNotBlank(shopJson)){// 3. 存在,直接返回Shop shop = JSONUtil.toBean(shopJson, Shop.class);return Result.ok(shop);}// 4. 不存在,根據(jù)id查詢(xún)數(shù)據(jù)庫(kù)Shop shop = getById(id);// 5. 不存在,寫(xiě)入redisif(shop == null){return Result.fail("店鋪不存在!");}// 6. 存在,寫(xiě)入redisstringRedisTemplate.opsForValue().set(redisKey,JSONUtil.toJsonStr(shop));// 7. 返回return Result.ok(shop);}

店鋪類(lèi)型查詢(xún)業(yè)務(wù)添加緩存練習(xí)題

@Overridepublic Result queryTypeList() {// 1. 從redis查詢(xún)店鋪類(lèi)別緩存List<String> shopTypeRedisKey = stringRedisTemplate.opsForList().range(RedisConstants.CACHE_SHOP_TYPE_KEY,0,-1);// 2. 判斷是否命中緩存if(!CollectionUtils.isEmpty(shopTypeRedisKey)){// 3. 存在,直接返回,即是命中緩存// 使用stream流將json集合轉(zhuǎn)為List<ShopType> shopTypeList = shopTypeRedisKey.stream().map(item -> JSONUtil.toBean(item, ShopType.class)).sorted(Comparator.comparingInt(ShopType::getSort)).collect(Collectors.toList());// 返回緩存數(shù)據(jù)return Result.ok(shopTypeList);}// 4. 不存在,查詢(xún)數(shù)據(jù)庫(kù)List<ShopType> shopTypes = query().orderByAsc("sort").list();// 判斷數(shù)據(jù)庫(kù)中是否有數(shù)據(jù)if(CollectionUtils.isEmpty(shopTypes)){// 不存在則緩存一個(gè)空集合,解決緩存穿透stringRedisTemplate.opsForValue().set(RedisConstants.CACHE_SHOP_TYPE_KEY, Collections.emptyList().toString(),RedisConstants.CACHE_NULL_TTL, TimeUnit.MINUTES);return Result.fail("商品分類(lèi)信息為空");}// 5. 數(shù)據(jù)存在,先寫(xiě)入redis,再返回// 使用stream流將bean集合轉(zhuǎn)為json集合List<String> shopTypeCache = shopTypes.stream().sorted(Comparator.comparingInt(ShopType::getSort)).map(item -> JSONUtil.toJsonStr(item)).collect(Collectors.toList());stringRedisTemplate.opsForList().rightPushAll(RedisConstants.CACHE_SHOP_TYPE_KEY,shopTypeCache);stringRedisTemplate.expire(RedisConstants.CACHE_SHOP_TYPE_KEY,RedisConstants.CACHE_SHOP_TYPE_TTL, TimeUnit.MINUTES);// 6. 返回(按類(lèi)別升序排序)return Result.ok(shopTypes);}

緩存更新策略

在這里插入圖片描述
在這里插入圖片描述
在這里插入圖片描述
操作緩存和數(shù)據(jù)庫(kù)的順序,不論誰(shuí)先進(jìn)行都可能會(huì)有線程安全的問(wèn)題
在這里插入圖片描述

但方案二的發(fā)生可能性更小,所以更優(yōu)
總結(jié):
在這里插入圖片描述

給查詢(xún)商鋪的緩存添加超時(shí)剔除和主動(dòng)更新的策略

在這里插入圖片描述
查詢(xún)店鋪:

  @Overridepublic Result queryById(Long id) {String redisKey = RedisConstants.CACHE_SHOP_KEY + id;// 1. 從redis查詢(xún)商鋪緩存String shopJson = stringRedisTemplate.opsForValue().get(redisKey);// 2. 判讀是否存在if(StrUtil.isNotBlank(shopJson)){// 3. 存在,直接返回Shop shop = JSONUtil.toBean(shopJson, Shop.class);return Result.ok(shop);}// 4. 不存在,根據(jù)id查詢(xún)數(shù)據(jù)庫(kù)Shop shop = getById(id);// 5. 不存在,返回錯(cuò)誤if(shop == null){return Result.fail("店鋪不存在!");}// 6. 存在,寫(xiě)入redisstringRedisTemplate.opsForValue().set(redisKey,JSONUtil.toJsonStr(shop), RedisConstants.CACHE_SHOP_TTL, TimeUnit.MINUTES);// 7. 返回return Result.ok(shop);}

修改店鋪:

@Override@Transactionalpublic Result update(Shop shop) {Long id = shop.getId();if(id == null){return Result.fail("店鋪id不能為空");}// 更新數(shù)據(jù)庫(kù),在刪除緩存updateById(shop);// 刪除緩存stringRedisTemplate.delete(RedisConstants.CACHE_SHOP_KEY + id);return Result.ok();}

緩存穿透

客戶端請(qǐng)求的數(shù)據(jù)在緩存和數(shù)據(jù)庫(kù)中都不存在,這樣緩存永遠(yuǎn)不會(huì)生效,這些請(qǐng)求都會(huì)打到數(shù)據(jù)庫(kù)

在這里插入圖片描述

緩存空對(duì)象

在這里插入圖片描述
可以設(shè)置一個(gè)TTL,解決內(nèi)存消耗問(wèn)題
可能存在短期不一致的問(wèn)題,控制TTL的時(shí)間,可以一定程度的緩解這個(gè)問(wèn)題。

布隆過(guò)濾

客戶端個(gè)redis之間,在加一層過(guò)濾——布隆過(guò)濾器——哈希算法二進(jìn)制位保存數(shù)據(jù)
布隆過(guò)濾器說(shuō)如果不存在一定是不存在,但存在不一定是100% 的
在這里插入圖片描述
先看一下之前查詢(xún)商鋪信息的業(yè)務(wù)流程
在這里插入圖片描述
物品們采用方案一應(yīng)該把空數(shù)據(jù)寫(xiě)入redis

在這里插入圖片描述
在這里插入圖片描述

緩存雪崩

在這里插入圖片描述

解決方案

  • 給不同的key的TTL添加隨機(jī)值——針對(duì)問(wèn)題一
  • 利用redis集群提高服務(wù)的可用性——針對(duì)問(wèn)題二
  • 給緩存業(yè)務(wù)添加降級(jí)限流策略
  • 給業(yè)務(wù)添加多級(jí)緩存

緩存擊穿

在這里插入圖片描述

解決方案

互斥鎖和邏輯過(guò)期
在這里插入圖片描述
在這里插入圖片描述

基于互斥鎖方式解決緩存擊穿問(wèn)題

在這里插入圖片描述
獲取鎖:
- redis的setnx指令可以在key不存在的時(shí)候?qū)?#xff0c;存在的時(shí)候不能寫(xiě),就類(lèi)似于互斥
釋放鎖:
- 刪掉就行了
設(shè)置鎖的時(shí)候要設(shè)置有效期,避免因?yàn)槟撤N原因鎖得不到釋放

 @Overridepublic Result queryById(Long id) {// 緩存穿透
//        Shop shop = queryWithPassThrough(id);// 互斥鎖解決緩存擊穿Shop shop = queryWithMutex(id);if(shop == null){return Result.fail("店鋪不存在!");}// 7. 返回return Result.ok(shop);}/*** 解決緩存擊穿(互斥鎖)的寫(xiě)法* @param id* @return*/public Shop queryWithMutex(Long id){String redisKey = RedisConstants.CACHE_SHOP_KEY + id;// 1. 從redis查詢(xún)商鋪緩存String shopJson = stringRedisTemplate.opsForValue().get(redisKey);// 2. 判讀是否存在if(StrUtil.isNotBlank(shopJson)){// 3. 存在,直接返回return JSONUtil.toBean(shopJson, Shop.class);}// 命中的是否是空值if(shopJson != null){// 返回一個(gè)錯(cuò)誤信息return null;}//4. 開(kāi)始實(shí)現(xiàn)緩存重建// 4.1 獲取互斥鎖String lockKey = "lock:shop:" + id;Shop shop = null;try{boolean isLock = tryLock(lockKey);// 4.2 判斷是否獲取成功if(!isLock){// 4.3 如果失敗,則休眠并重試Thread.sleep(50);return queryWithMutex(id);}// 4.4 如果成功,根據(jù)id查詢(xún)數(shù)據(jù)庫(kù)shop = getById(id);// 模擬重建的延時(shí)——測(cè)試的時(shí)候打開(kāi)
//            Thread.sleep(200);// 5. 不存在,返回錯(cuò)誤if(shop == null){// 將空值寫(xiě)入redis——解決緩存穿透stringRedisTemplate.opsForValue().set(redisKey,"",RedisConstants.CACHE_NULL_TTL,TimeUnit.MINUTES);// 返回錯(cuò)誤信息return null;}// 6. 存在,寫(xiě)入redisstringRedisTemplate.opsForValue().set(redisKey,JSONUtil.toJsonStr(shop), RedisConstants.CACHE_SHOP_TTL, TimeUnit.MINUTES);} catch (InterruptedException e){throw new RuntimeException(e);}finally {// 釋放互斥鎖unLock(lockKey);}// 7. 返回return shop;}private boolean tryLock(String key){Boolean flag = stringRedisTemplate.opsForValue().setIfAbsent(key, "1", 10, TimeUnit.SECONDS);return BooleanUtil.isTrue(flag);  // 因?yàn)閒lag是封裝類(lèi),而要求的返回值是基本數(shù)據(jù)類(lèi)型,在返回的時(shí)候就會(huì)進(jìn)行自動(dòng)的拆箱,拆箱的時(shí)候會(huì)出現(xiàn)空指針}private void unLock(String key){stringRedisTemplate.delete(key);}

基于邏輯過(guò)期的方式解決緩存擊穿問(wèn)題

在這里插入圖片描述

有個(gè)小問(wèn)題,我們想要給存入redis的數(shù)據(jù)添加過(guò)期時(shí)間,但是我們的Shop實(shí)體類(lèi)中又沒(méi)有過(guò)期時(shí)間這個(gè)字段怎么辦呢?
我們?nèi)ソo這個(gè)Shop實(shí)體添加過(guò)期時(shí)間字段可行嗎?可行,但是對(duì)代碼有侵入性,而且這個(gè)字段除了這里其他地方都用不到。
那怎么辦?
我們可以聲明一個(gè)RedisData的實(shí)體類(lèi),里面有一個(gè)過(guò)期時(shí)間的屬性,讓Shop繼承這個(gè)實(shí)體類(lèi),Shop也就有了過(guò)期時(shí)間的屬性了,但還是有一點(diǎn)點(diǎn)不好,還是需要修改源代碼,需要修改Shop,有一定的侵入性,雖然也蠻好的。
還有一種方案:在RedisData中在聲明一個(gè)Object的字段,把想要存儲(chǔ)的數(shù)據(jù)放到Object中。

@Data
public class RedisData {private LocalDateTime expireTime;private Object data;
}

實(shí)際的項(xiàng)目肯定會(huì)有管理系統(tǒng)在后臺(tái)點(diǎn)擊,把熱點(diǎn)數(shù)據(jù)提前緩存進(jìn)redis,我們這里用一個(gè)單元測(cè)試完成這個(gè)功能。
先寫(xiě)一個(gè)緩存進(jìn)redis的方法

    public void saveShop2Redis(Long id, Long expireSeconds){// 1. 查詢(xún)店鋪數(shù)據(jù)Shop shop = getById(id);// 2. 封裝邏輯過(guò)期時(shí)間RedisData redisData = new RedisData();redisData.setData(shop);redisData.setExpireTime(LocalDateTime.now().plusSeconds(expireSeconds));///3.寫(xiě)入redisstringRedisTemplate.opsForValue().set(RedisConstants.CACHE_SHOP_KEY + id, JSONUtil.toJsonStr(redisData));}

在編寫(xiě)一個(gè)單元測(cè)試

@SpringBootTest
class HmDianPingApplicationTests {@Autowiredprivate ShopServiceImpl shopService;@Testvoid testSaveShop() {shopService.saveShop2Redis(1L, 10L);}}

下面我們完成基于邏輯過(guò)期的方式解決緩存擊穿的商鋪查詢(xún)的代碼

// 使用線程池來(lái)開(kāi)辟新線程private static final ExecutorService CACHE_REBUILD_EXECUTOR = Executors.newFixedThreadPool(10);/*** 解決緩存擊穿(邏輯過(guò)期)的寫(xiě)法* @param id* @return*/public Shop queryWithLogicalExpire(Long id){String redisKey = RedisConstants.CACHE_SHOP_KEY + id;// 1. 從redis查詢(xún)商鋪緩存String shopJson = stringRedisTemplate.opsForValue().get(redisKey);// 2. 判讀是否存在if(StrUtil.isBlank(shopJson)){// 3. 不存在,直接返回return null;}// 4. 命中需要判斷過(guò)期時(shí)間,需要先把json反序列化位對(duì)象RedisData redisData = JSONUtil.toBean(shopJson, RedisData.class);JSONObject jsonData = (JSONObject) redisData.getData(); // 如果不強(qiáng)轉(zhuǎn)就是一個(gè)Object,但本質(zhì)上是JSONObject,所以先轉(zhuǎn)成JSONObjectShop shop = JSONUtil.toBean(jsonData, Shop.class);LocalDateTime expireTime = redisData.getExpireTime();// 5. 判斷是否過(guò)期if(expireTime.isAfter(LocalDateTime.now())){// 5.1 未過(guò)期,直接返回店鋪信息return shop;}// 5.2 已過(guò)期,需要緩存重建// 6. 緩存重建// 6.1 獲取互斥鎖String lockKey = RedisConstants.LOCK_SHOP_KEY + id;boolean isLock = tryLock(lockKey);// 6.2 判斷是否獲取鎖成功if(isLock){//6.3成功 開(kāi)啟獨(dú)立線程實(shí)現(xiàn)緩存重建CACHE_REBUILD_EXECUTOR.submit(()->{try {// 重建緩存this.saveShop2Redis(id,20L);}catch (Exception e){} finally {// 釋放鎖unLock(lockKey);}});}// 6.4 返回過(guò)期的商鋪信息return shop;}

緩存工具封裝

在這里插入圖片描述
把封裝的代碼放到CacheClient這個(gè)類(lèi)中,并添加@Component注解,把這個(gè)bean交給Spring管理,封裝的工具類(lèi)如下:


@Slf4j
@Component
public class CacheClient {private final StringRedisTemplate stringRedisTemplate;// 用構(gòu)造器注入public CacheClient(StringRedisTemplate stringRedisTemplate){this.stringRedisTemplate = stringRedisTemplate;}public void set(String key, Object value, Long time, TimeUnit unit){stringRedisTemplate.opsForValue().set(key, JSONUtil.toJsonStr(value),time,unit);}public void setWithLogicalExpire(String key, Object value, Long time, TimeUnit unit){// 設(shè)置邏輯過(guò)期RedisData redisData = new RedisData();redisData.setData(value);redisData.setExpireTime(LocalDateTime.now().plusSeconds(unit.toSeconds(time)));// 寫(xiě)入RedisstringRedisTemplate.opsForValue().set(key, JSONUtil.toJsonStr(redisData));}public <R, ID> R queryWithPassThrough(String keyPrefix, ID id, Class<R> type, Function<ID, R> dbFallback, Long time, TimeUnit unit){String redisKey = keyPrefix + id;// 1. 從redis查詢(xún)商鋪緩存String json = stringRedisTemplate.opsForValue().get(redisKey);// 2. 判讀是否存在if(StrUtil.isNotBlank(json)){// 3. 存在,直接返回return JSONUtil.toBean(json, type);}// 命中的是否是空值if(json != null){// 返回一個(gè)錯(cuò)誤信息return null;}// 4. 不存在,根據(jù)id查詢(xún)數(shù)據(jù)庫(kù)——我們哪知道去查哪個(gè)數(shù)據(jù)庫(kù),只能調(diào)用者告訴我們,——函數(shù)式編程R r = dbFallback.apply(id);// 5. 不存在,返回錯(cuò)誤if(r == null){// 將空值寫(xiě)入redis——解決緩存穿透stringRedisTemplate.opsForValue().set(redisKey,"",RedisConstants.CACHE_NULL_TTL,TimeUnit.MINUTES);// 返回錯(cuò)誤信息return null;}// 6. 存在,寫(xiě)入redisthis.set(redisKey, r, time, unit);// 7. 返回return r;}private static final ExecutorService CACHE_REBUILD_EXECUTOR = Executors.newFixedThreadPool(10);public <R,ID> R queryWithLogicalExpire(String keyPrefix, ID id, Class<R> type, Function<ID, R> dbFallback, Long time, TimeUnit unit){String redisKey = keyPrefix + id;// 1. 從redis查詢(xún)商鋪緩存String json = stringRedisTemplate.opsForValue().get(redisKey);// 2. 判讀是否存在if(StrUtil.isBlank(json)){// 3. 不存在,直接返回return null;}// 4. 命中需要判斷過(guò)期時(shí)間,需要先把json反序列化位對(duì)象RedisData redisData = JSONUtil.toBean(json, RedisData.class);JSONObject jsonData = (JSONObject) redisData.getData(); // 如果不強(qiáng)轉(zhuǎn)就是一個(gè)Object,但本質(zhì)上是JSONObject,所以先轉(zhuǎn)成JSONObjectR r = JSONUtil.toBean(jsonData, type);LocalDateTime expireTime = redisData.getExpireTime();// 5. 判斷是否過(guò)期if(expireTime.isAfter(LocalDateTime.now())){// 5.1 未過(guò)期,直接返回店鋪信息return r;}// 5.2 已過(guò)期,需要緩存重建// 6. 緩存重建// 6.1 獲取互斥鎖String lockKey = RedisConstants.LOCK_SHOP_KEY + id;boolean isLock = tryLock(lockKey);// 6.2 判斷是否獲取鎖成功if(isLock){//6.3成功 開(kāi)啟獨(dú)立線程實(shí)現(xiàn)緩存重建CACHE_REBUILD_EXECUTOR.submit(()->{try {// 重建緩存// 先查數(shù)據(jù)庫(kù)R r1 = dbFallback.apply(id);// 寫(xiě)入redisthis.setWithLogicalExpire(redisKey, r1, time, unit);}catch (Exception e){} finally {// 釋放鎖unLock(lockKey);}});}// 6.4 返回過(guò)期的商鋪信息return r;}private boolean tryLock(String key){Boolean flag = stringRedisTemplate.opsForValue().setIfAbsent(key, "1", 10, TimeUnit.SECONDS);return BooleanUtil.isTrue(flag);  // 因?yàn)閒lag是封裝類(lèi),而要求的返回值是基本數(shù)據(jù)類(lèi)型,在返回的時(shí)候就會(huì)進(jìn)行自動(dòng)的拆箱,拆箱的時(shí)候會(huì)出現(xiàn)空指針}private void unLock(String key){stringRedisTemplate.delete(key);}}

封裝這個(gè)工具類(lèi),有很多的技巧要總結(jié):

  1. 傳遞的參數(shù)和返回的數(shù)據(jù)類(lèi)型要泛型
  2. 函數(shù)式編程:在封裝queryWithPassThrough的時(shí)候,里面在redis查詢(xún)不存在的時(shí)候,我們要去查詢(xún)數(shù)據(jù)庫(kù),那查詢(xún)數(shù)據(jù)庫(kù)的代碼,我們泛型傳遞的參數(shù),調(diào)用哪個(gè)查詢(xún)數(shù)據(jù)庫(kù)的函數(shù)去查詢(xún)數(shù)據(jù)庫(kù)呢?這時(shí)要用函數(shù)式編程,把要用到的函數(shù)通過(guò)參數(shù)傳遞過(guò)來(lái),有參數(shù)有返回值就用Function<ID, R> dbFallback,使用的時(shí)候直接R r = dbFallback.apply(id);即可,調(diào)用這個(gè)工具方法的時(shí)候把具體的查詢(xún)函數(shù)作為參數(shù)傳進(jìn)去。

那這些工具類(lèi)在調(diào)用的時(shí)候又該怎么調(diào)用呢?

  @Overridepublic Result queryById(Long id) {// 緩存穿透
//        Shop shop = cacheClient.queryWithPassThrough(RedisConstants.CACHE_SHOP_KEY, id, Shop.class, this::getById, RedisConstants.CACHE_SHOP_TTL, TimeUnit.MINUTES);// 邏輯過(guò)期解決緩存擊穿問(wèn)題Shop shop = cacheClient.queryWithLogicalExpire(RedisConstants.CACHE_SHOP_KEY, id, Shop.class, this::getById, 20L, TimeUnit.SECONDS);if(shop == null){return Result.fail("店鋪不存在!");}// 7. 返回return Result.ok(shop);}

那我們的緩存擊穿想測(cè)試的話,還是得先用單元測(cè)試的方法,先往redis中寫(xiě)入點(diǎn)熱點(diǎn)數(shù)據(jù),現(xiàn)在就可以改進(jìn)我們的單元測(cè)試代碼


@SpringBootTest
class HmDianPingApplicationTests {@Autowiredprivate CacheClient cacheClient;@Testvoid testSaveShop() {Shop shop = shopService.getById(1L);cacheClient.setWithLogicalExpire(RedisConstants.CACHE_SHOP_KEY + 1L,shop,10L, TimeUnit.SECONDS);}
}
http://www.risenshineclean.com/news/7535.html

相關(guān)文章:

  • 國(guó)內(nèi)外優(yōu)秀建筑設(shè)計(jì)網(wǎng)站濟(jì)南優(yōu)化網(wǎng)站的哪家好
  • 提供深圳網(wǎng)站制作公司廣告搜索引擎
  • 創(chuàng)意福州網(wǎng)站建設(shè)appstore關(guān)鍵詞優(yōu)化
  • 做網(wǎng)站需要找人優(yōu)化嗎百度app下載安裝官方免費(fèi)下載
  • 網(wǎng)站制作什么樣的字體好看什么是seo推廣
  • 讓其他公司做網(wǎng)站應(yīng)注意什么問(wèn)題桂林seo排名
  • 吉林省建筑市場(chǎng)監(jiān)管公共服務(wù)平臺(tái)朝陽(yáng)seo
  • 外國(guó)排版網(wǎng)站網(wǎng)絡(luò)營(yíng)銷(xiāo)什么意思
  • 網(wǎng)站建設(shè)鏈接演示湖北百度推廣電話
  • 南寧網(wǎng)站建設(shè)seo友鏈交換網(wǎng)站源碼
  • 做模具做什么網(wǎng)站信息流廣告案例
  • 西寧網(wǎng)站建設(shè)公司排行株洲seo快速排名
  • 校園網(wǎng)站群建設(shè)搜索引擎優(yōu)化入門(mén)
  • 生日禮物自己做網(wǎng)站南昌seo優(yōu)化公司
  • 周口哪家做網(wǎng)站好湖南平臺(tái)網(wǎng)站建設(shè)制作
  • 網(wǎng)站開(kāi)發(fā)術(shù)語(yǔ)長(zhǎng)沙網(wǎng)站推廣智投未來(lái)
  • 潮州市建設(shè)局官方網(wǎng)站下拉詞排名
  • wordpress置頂文章全文顯示seo怎樣
  • 做快消品看那些網(wǎng)站好外貿(mào)網(wǎng)站平臺(tái)都有哪些
  • 自建網(wǎng)站模板營(yíng)銷(xiāo)外包
  • 網(wǎng)站建設(shè)網(wǎng)站建設(shè)網(wǎng)站運(yùn)營(yíng)與維護(hù)
  • 現(xiàn)在在市場(chǎng)上做網(wǎng)站怎么樣哪個(gè)平臺(tái)做推廣效果好
  • 網(wǎng)站到期怎么續(xù)費(fèi)網(wǎng)上商城推廣13種方法
  • 自己怎么做彩票網(wǎng)站整站優(yōu)化包年
  • wordpress做外貿(mào)網(wǎng)站的劣勢(shì)北京優(yōu)化網(wǎng)站方法
  • 市住房住房城鄉(xiāng)建設(shè)委官方網(wǎng)站友鏈網(wǎng)
  • 大連網(wǎng)站建設(shè)怎么做精準(zhǔn)營(yíng)銷(xiāo)推廣方案
  • 網(wǎng)站平臺(tái)建設(shè)招標(biāo)書(shū)百度seo優(yōu)化服務(wù)項(xiàng)目
  • 廣東省建設(shè)執(zhí)業(yè)資格注冊(cè)中心官方網(wǎng)站百度新聞?lì)^條
  • 網(wǎng)站免費(fèi)虛擬主機(jī)申請(qǐng)外貿(mào)seo優(yōu)化公司