1.緩存分析
我們已經(jīng)實(shí)現(xiàn)了商品詳情頁(yè)面的展示慎玖,但是有一個(gè)問(wèn)題我們要思考的是:因?yàn)椴樵兩唐吩斍榈臅r(shí)候要涉及到數(shù)據(jù)庫(kù)枣察,如果我們網(wǎng)頁(yè)的訪問(wèn)量很大的時(shí)候阳藻,查詢商品都去查數(shù)據(jù)庫(kù)的話鬼廓,數(shù)據(jù)庫(kù)的壓力是很大的肿仑。為了解決這個(gè)問(wèn)題的話我們要引入緩存;但是引入緩存的話又要考慮一個(gè)問(wèn)題碎税,緩存的資源也是有限的尤慰。如果我們把大量商品詳情信息都放到緩存的話,緩存的壓力也很大雷蹂。我們知道商品是分熱點(diǎn)商品和冷門商品的伟端,熱點(diǎn)訪問(wèn)量很大,因此存儲(chǔ)熱門商品信息才能提高緩存的利用率匪煌。那么如何解決這個(gè)問(wèn)題呢责蝠,有以下兩種方案:
1.利用redis的的訪問(wèn)量統(tǒng)計(jì)功能并利用其zset數(shù)據(jù)類型進(jìn)行訪問(wèn)量排序,把訪問(wèn)量高的商品詳情內(nèi)容添加到緩存當(dāng)中萎庭。這種方案比較麻煩霜医,我們不建議采用這種方式。
2.設(shè)置緩存的過(guò)期時(shí)間驳规,用戶只要點(diǎn)擊查看商品詳情肴敛,我們一律先都存放到緩存當(dāng)中,但是我們要設(shè)置一下該條商品的緩存時(shí)間(比如半天或一天或其它)吗购,到期后該商品的緩存就會(huì)被刪除掉医男,如果該商品是熱門商品的話,用戶再查看詳情的時(shí)候就又會(huì)向緩存中添加該商品的緩存捻勉,如果該商品是冷門商品镀梭,過(guò)期后緩存中便沒有這款商品的緩存信息了(直到有下一位用戶查看該商品的詳情信息),這樣就可以節(jié)約緩存的空間踱启,而且這種方式無(wú)疑是提高緩存利用率最簡(jiǎn)單的方法了报账。
那么我們?nèi)绾卧诰彺嬷斜4嫖覀兊男畔⒛兀?br>
redis有兩種存儲(chǔ)方式撒强,一種是哈希,一種是字符串笙什;前者適合信息分類存儲(chǔ),但不適合設(shè)置緩存的過(guò)期時(shí)間胚想,因?yàn)樗恢С值骄唧w到對(duì)每個(gè)Field進(jìn)行設(shè)置過(guò)期時(shí)間琐凭,這就意味著如果我們?cè)O(shè)置的key過(guò)期后,緩存的消息都會(huì)消失浊服,這顯然是不合理的统屈,我們想要的是針對(duì)每個(gè)商品設(shè)置過(guò)期時(shí)間,因此設(shè)置過(guò)期時(shí)間的話牙躺,hash存儲(chǔ)不合適愁憔。String存儲(chǔ)是比較適合的,那么問(wèn)題又來(lái)了孽拷,String存儲(chǔ)時(shí)key是容易重復(fù)的吨掌,怎么來(lái)避免key沖突呢?我們可以通過(guò)添加前綴脓恕、后綴的方式對(duì)redis的key進(jìn)行分類膜宋,如下圖所示。既然是要存儲(chǔ)商品詳情炼幔,就在商品ID前面起個(gè)名字秋茫,就叫做ITEM_INFO(大家可以隨便起),在ID的后面添加后綴BASE(代表是基本信息)乃秀,DESC(代表是商品描述信息)
即:
ITEM_INFO:123456:BASE
ITEM_INFO:123456:DESC
如果把二維表保存到redis中:
1肛著、表名就是第一層
2、主鍵是第二層
3跺讯、字段名第三次
三層使用“:”分隔作為key枢贿,value就是字段中的內(nèi)容。
2.緩存的實(shí)現(xiàn)
我們一般把緩存加到service層中抬吟,因?yàn)镃ontroller層使用的話有一定的局限性萨咕。將緩存加到service層的話,如果是其他工程引用這個(gè)服務(wù)的話也能使用緩存的功能
下面是實(shí)現(xiàn)的步驟:
第一步:在taotao-manager-service中添加依賴
第二步:將taotao-content-service中的jedis的代碼復(fù)制一份
第三步:將配置文件復(fù)制進(jìn)去
第四步:配置resource.properties
從上面的分析我們知道我們可以通過(guò)添加緩存前綴來(lái)區(qū)分key的策略火本,這個(gè)key我們可以靈活一點(diǎn)危队,還有過(guò)期時(shí)間也是。因此我們?cè)趓esource.properties中配置
第四步:在代碼中添加緩存
package com.taotao.service.impl;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.taotao.common.pojo.EasyUIDataGridResult;
import com.taotao.common.pojo.TaotaoResult;
import com.taotao.mapper.TbItemDescMapper;
import com.taotao.mapper.TbItemMapper;
import com.taotao.pojo.TbItem;
import com.taotao.pojo.TbItemDesc;
import com.taotao.pojo.TbItemExample;
import com.taotao.service.ItemService;
import com.taotao.service.jedis.JedisClient;
import com.taotao.utils.IDUtils;
import com.taotao.utils.JsonUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.jms.core.JmsTemplate;
import org.springframework.jms.core.MessageCreator;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import javax.jms.*;
import java.util.Date;
import java.util.List;
/**
* 商品管理
*/
@Service
public class ItemServiceImpl implements ItemService {
@Autowired
private TbItemMapper tbItemMapper;
@Autowired
private TbItemDescMapper itemDescMapper;
@Autowired
private JmsTemplate jmsTemplate;
@Resource(name = "itemAddTopic")
private Destination itemAddTopic;
@Autowired
private JedisClient jedisClient;
@Value("${ITEM_INFO}")
private String ITEM_INFO;//商品的前綴
@Value("${ITEM_EXPIRE}")
private Integer ITEM_EXPIRE;//商品的后綴
@Override
public TbItem getItemById(long itemId) {
//查詢緩存
try{
String json = jedisClient.get(ITEM_INFO + ":"+ itemId + ":BASE");
if (StringUtils.isNotBlank(json)) {
TbItem item = JsonUtils.jsonToPojo(json,TbItem.class);
return item;
}
}catch(Exception e) {
e.printStackTrace();
}
TbItem item = tbItemMapper.selectByPrimaryKey(itemId);
//如果在緩存中沒有就添加進(jìn)緩存
try{
//添加緩存
jedisClient.set(ITEM_INFO + ":"+ itemId + ":BASE", JsonUtils.objectToJson(item));
//設(shè)置過(guò)期時(shí)間
jedisClient.expire(ITEM_INFO + ":"+ itemId + ":BASE",ITEM_EXPIRE);
}catch(Exception e) {
e.printStackTrace();
}
return item;
}
@Override
public TbItemDesc getDescById(long itemId) {
//查詢緩存
try{
String json = jedisClient.get(ITEM_INFO + ":" + itemId + ":DESC");
if(StringUtils.isNotBlank(json)) {
TbItemDesc desc = JsonUtils.jsonToPojo(json,TbItemDesc.class);
return desc;
}
}catch(Exception e) {
}
TbItemDesc desc = itemDescMapper.selectByPrimaryKey(itemId);
//如果在緩存中沒有就添加進(jìn)緩存
try{
jedisClient.set(ITEM_INFO + ":" + itemId + ":DESC",JsonUtils.objectToJson(desc));
jedisClient.expire(ITEM_INFO + ":" + itemId + ":DESC",ITEM_EXPIRE);
}catch(Exception e) {
e.printStackTrace();
}
return desc;
}
@Override
public EasyUIDataGridResult getItemList(int page, int rows) {
//1.在執(zhí)行查詢之前配置分頁(yè)條件钙畔。使用PageHelper的靜態(tài)方法
PageHelper.startPage(page,rows);
//2.執(zhí)行查詢
TbItemExample tbItemExample = new TbItemExample();
List<TbItem> list = tbItemMapper.selectByExample(tbItemExample);
//3.創(chuàng)建PageInfo對(duì)象
PageInfo<TbItem> pageInfo = new PageInfo<>(list);
EasyUIDataGridResult result = new EasyUIDataGridResult();
//設(shè)置數(shù)目
result.setTotal(pageInfo.getTotal());
//設(shè)置返回的數(shù)據(jù)
result.setRows(list);
return result;
}
@Override
public TaotaoResult addItem(TbItem item, String desc) {
final long id = IDUtils.genItemId();
item.setId(id);
item.setCreated(new Date());
item.setUpdated(new Date());
item.setStatus((byte) 1);
tbItemMapper.insert(item);
TbItemDesc itemDesc = new TbItemDesc();
itemDesc.setItemDesc(desc);
itemDesc.setCreated(new Date());
itemDesc.setUpdated(new Date());
itemDescMapper.insert(itemDesc);
//使用ActiveMq發(fā)送消息
jmsTemplate.send(itemAddTopic,new MessageCreator() {
@Override
public Message createMessage(Session session) throws JMSException {
TextMessage textMessage = session.createTextMessage(id + "");
return textMessage;
}
});
return TaotaoResult.ok();
}
@Override
public TbItem updateItem(long itemId) {
return null;
}
}